better-dsh 0.3.1-f → 0.3.2

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.
@@ -8,21 +8,27 @@ Better Dash and Super Dash each provide the native `remote` tool and REPL route.
8
8
  | --- | --- |
9
9
  | List locally known targets without dialing | `{}` |
10
10
  | Probe one target | `{target:"ssh:alias"}` |
11
- | Register an Agent-local SSH identity | `{target:"byossh:build",ssh:{host:"host",user:"user",key:"/origin/key"}}` |
12
- | Stateless command and stdin | `{target:"byossh:build",cmd:"cat",stdin:"hello"}` |
13
- | Stream a local script to fixed `bash -s` | `{target:"ssh:alias",script:"/absolute/script.sh"}` |
14
- | Persistent shell | `{target:"ssh:alias",mode:"pty",cmd:"cd /tmp; export CHECK=ready"}` |
15
- | Official background job | `{target:"ssh:alias",cmd:"long-command",run_in_background:true}` |
11
+ | Register an Agent-local SSH identity (no dialing) | `{target:"ssh:build",ssh:{host:"host",user:"user",key:"/origin/key"}}`; omit `target` for an auto id (`ssh-xxxx`) |
12
+ | Stateless command and stdin over an identity | `{target:"ssh:build",cmd:"cat",stdin:"hello"}` |
13
+ | Stream a local script to fixed `bash -s` | `{target:"ssh:alias",scriptPath:"/absolute/script.sh"}` |
14
+ | Create a persistent shell (tab semantics) | `{target:"ssh:alias:pty",cmd:"cd /tmp; export CHECK=ready"}`; append `:label` (`ssh:alias:pty:build`) to name it |
15
+ | Reuse a persistent shell | `{target:"pty:<id\|label>",cmd:"…"}` |
16
+ | Session card (state + ledger, no command) | `{target:"pty:<id\|label>"}` |
17
+ | Create a BYO PTY from a spawn command | `{spawn:"docker exec -it img bash",target:"pty:build",cmd:"…"}`; later `{target:"pty:build",cmd:"…"}` |
18
+ | Background job (oneshot or PTY) | `{target:"ssh:alias",cmd:"long-command",run_in_background:true}` |
19
+ | Close a PTY session | `{action:"close",target:"pty:<id\|label>",force:true}` |
16
20
  | Native CLI copy | `{action:"copy",src:"/absolute/source",dst:"ssh:alias:/absolute/destination",argv:["-p"]}` |
17
21
  | Native rsync | `{action:"rsync",src:"/absolute/source/",dst:"ssh:alias:/existing/destination/",argv:["-a","--partial","--dry-run"]}` |
18
22
 
19
- `script` cannot combine with cmd/stdin/spawn/PTY. Direct local command execution is not provided; use native local shell tools. Background jobs are oneshot-only, require the official jobs service/controller, and are read/killed with `job_output`/`job_kill`; they have no default foreground timeout. An explicit timeout still applies. SSH keys/config stay on the origin; BYO identities are not persisted across new/cold Agents. PTY backlog recovery and live probes are not part of this release.
23
+ `mode` no longer exists: append `:pty` to a transport target to create, address a live shell as `pty:<id|label>`. `scriptPath` cannot combine with cmd/stdin/spawn/PTY. Direct local command execution is not provided; use native local shell tools. Background jobs require the official jobs service/controller and are read/killed with `job_output`/`job_kill`; on PTY lanes a background job's jobId is the commandId (a timeout handoff keeps them as separate ledger fields). SSH keys/config stay on the origin; BYO identities are not persisted across new/cold Agents. PTY backlog recovery and live probes are not part of this release.
24
+
25
+ PTY state is durable and readable: every dispatch returns exit, cwd and `envDelta` (variable names and change markers only — values never leave the endpoint; fetch them yourself if needed). `close` is idempotent (`closed:false, reason:"not-found"|"already-closed-or-reaped"`); a session with a running job refuses close unless `force:true`, which kills the group and reports `killed`. A busy session rejects new commands instead of queueing; open another PTY or use a oneshot. Idle PTYs are reaped after 15 minutes; an Agent holds at most 10 live sessions across connections, and dead sessions do not count. `hub:<m4>:pty` selects the Hub lane's PTY but exposes no session id, label, parallelism or background works there.
20
26
 
21
27
  Native/PTY output retains at most 4,000,000 UTF-16 units per stream; Hub oneshot retains 4 MiB bytes. Normal returned tails are smaller. Read `outputStats` units and dropped/returned counters rather than treating character counts as bytes. Discarded output is not recoverable after restart.
22
28
 
23
29
  ## File operations: native CLI semantics
24
30
 
25
- `remote` addresses targets once (`ssh:<name>`, `byossh:<label>`, `docker:<name>`, `incus:<name>`, `hub:<machine>`, local paths) and hands the actual transfer to the native CLI. `argv` is an ordered array of native option tokens — one element = one argv token, appended verbatim before the parsed `src`/`dst`. There is no option whitelist, no shell parsing, and no forced defaults: no hidden `--dry-run`, no forced archive/timeout, no automatic verification. A dry run means passing `--dry-run` yourself; unknown or incompatible options fail in the native CLI and its exit code and stderr come back as-is. Success of a native command is never reported as independently verified — `verified:false` on native copy receipts means exactly that.
31
+ `remote` addresses targets once (`ssh:<name>`, `ssh:<label>` for a BYO identity, `docker:<name>`, `incus:<name>`, `hub:<machine>`, local paths) and hands the actual transfer to the native CLI. `argv` is an ordered array of native option tokens — one element = one argv token, appended verbatim before the parsed `src`/`dst`. There is no option whitelist, no shell parsing, and no forced defaults: no hidden `--dry-run`, no forced archive/timeout, no automatic verification. A dry run means passing `--dry-run` yourself; unknown or incompatible options fail in the native CLI and its exit code and stderr come back as-is. Success of a native command is never reported as independently verified — `verified:false` on native copy receipts means exactly that.
26
32
 
27
33
  ### copy routes
28
34
 
@@ -39,7 +45,7 @@ The native CLIs do not create destination parents or verify results on their own
39
45
 
40
46
  ### rsync routes
41
47
 
42
- rsync supports SSH/byossh endpoints with at most one local endpoint. Local↔SSH runs `rsync` on the origin with the endpoint's SSH identity wired through `RSYNC_RSH`; an explicit `-e`/`--rsh` in `argv` replaces that wiring per rsync's own rules (the command must then carry its own port/key/config). Nothing else is injected — no archive, no timeout, no dry-run, no remote owner, no `--rsync-path`.
48
+ rsync supports SSH endpoints (native aliases and BYO identities) with at most one local endpoint. Local↔SSH runs `rsync` on the origin with the endpoint's SSH identity wired through `RSYNC_RSH`; an explicit `-e`/`--rsh` in `argv` replaces that wiring per rsync's own rules (the command must then carry its own port/key/config). Nothing else is injected — no archive, no timeout, no dry-run, no remote owner, no `--rsync-path`.
43
49
 
44
50
  SSH↔SSH prefers the native forwarding route: the destination runs a temporary loopback-only rsync daemon, `ssh -L` brings it to an origin port, `ssh -R` carries it onto the source's loopback, and the source's own native rsync client performs one protocol conversation through the chain. The origin only forwards rsync protocol bytes; the destination's existing file data feeds real delta matching (`--stats` shows Matched data dominating for a small change on a large file). If an endpoint refuses TCP forwarding (`AllowTcpForwarding no`), a standard-stream route would be attempted; on the current OpenSSH/rsync combination (10.2 / 3.4.1) that route reports itself unavailable — the error says so and nothing is copied. rsync never falls back to a full copy or to Python.
45
51
 
@@ -51,6 +57,6 @@ File operations require the corresponding CLI on the origin (`scp`, `rsync`, `do
51
57
 
52
58
  ## One-shot command requirements
53
59
 
54
- One-shot SSH/byossh commands (foreground, background, script and literal stdin) run through ONE native SSH exec: the command executes under bash with a small POSIX wrapper whose TERM/HUP trap kills the command's whole process group, so backgrounded children do not outlive the session teardown. Remote prerequisites: bash (POSIX) — **no Python, no owner/lease protocol, no flock/monotonic clock, no extra sessions**. On normal completion the wrapper's EXIT trap reaps the command's whole process group (backgrounded children included — they neither outlive the call nor hold the channel open), and the exit code passes through verbatim. On timeout/cancellation the local transport dies at once and a dedicated cleanup session reads the pidfile the wrapper left and kills the group (TERM→KILL); sshd delivers no signal to a no-PTY session, so this explicit cleanup is the remote kill path.
60
+ One-shot SSH commands (native alias or BYO identity; foreground, background, scriptPath and literal stdin) run through ONE native SSH exec: the command executes under bash with a small POSIX wrapper whose TERM/HUP trap kills the command's whole process group, so backgrounded children do not outlive the session teardown. Remote prerequisites: bash (POSIX) — **no Python, no owner/lease protocol, no flock/monotonic clock, no extra sessions**. On normal completion the wrapper's EXIT trap reaps the command's whole process group (backgrounded children included — they neither outlive the call nor hold the channel open), and the exit code passes through verbatim. On timeout/cancellation the local transport dies at once and a dedicated cleanup session reads the pidfile the wrapper left and kills the group (TERM→KILL); sshd delivers no signal to a no-PTY session, so this explicit cleanup is the remote kill path.
55
61
 
56
62
  Docker/Incus one-shots use the same pure-CLI lane (`docker exec` / `incus exec` with the same wrapper); container prerequisites are the container's own bash. PTY paths are unchanged (`ssh -tt bash`, docker via script(1), incus interactive) and never required Python.
@@ -1,5 +1,7 @@
1
1
  # remote-pty-label Specification
2
2
 
3
+ > **Superseded(2026-10-19)**:本 spec 的 `byop:<label>` 入口、`mode` 锁定、`p:<label>` 池键与「同 label 复用」语义已被 [PTY Workbench v2 计划](../../superpowers/plans/2026-10-19-pty-workbench.md) 取代:BYO-PTY 并入 `pty:` selector(`spawn` 在场 = BYO)、`byossh:`/`byop:` 前缀移除、`mode` 字段移除且未知参数不强制拒绝、label 与机器名统一池、id 为 `pty-xxxx` / `ssh-xxxx`。下文保留为历史契约参照。
4
+
3
5
  ## Purpose
4
6
 
5
7
  `remote` 工具的持久化 BYO-PTY 通道从「`spawn` 命令原文即会话键」改为「`target` 选择器寻址的具名会话」。旧实现的池键就是整条 spawn 文本,于是「同一条命令」与「同一个会话」被绑死:改一个 token 就**静默**新开一个 shell(cwd/env 全丢、零提示),roster 又拿整整一条 shell 命令当会话名。本规格固定新契约——`byop:<label>` 是唯一入口、label 由调用方(模型)自选并因此成为复用入口、`spawn` 降格为该 label 首次创建时的伴生参数——并据此定义创建/复用/冲突三分支、失败面,以及裸名候选表的末位新增项。
@@ -2,6 +2,7 @@
2
2
 
3
3
  - 日期:2026-10-10(Asia/Hong_Kong)
4
4
  - 状态:2026-10-10 user 已审阅并明确授权执行;Task0–7 已独立审阅通过;Task8 完整双包消费者验收进行中,L 实装暴露的 worker/SSH cleanup 缺陷已进入修复验证。用户亲验与发布尚未放行。
5
+ - 0.3.2-b 对齐(2026-10-19):`script` 已定名 `scriptPath`;`mode` 字段已移除(用 `<transport>:pty[:label]` 创建、`pty:<id|label>` 复用);`byossh:`/`byop:` 前缀已移除(`ssh`/`spawn` 参数在场即 BYO)。下文旧调用形仅作历史。
5
6
  - 输入:[2026-10-09 方向稿](../../10_plans/2026-10-09-remote-tool-optimization-directions.md)及 2026-10-10 会话裁决。
6
7
  - 执行计划:[2026-10-10-remote-tool-enhancement.md](../../superpowers/plans/2026-10-10-remote-tool-enhancement.md)。本规格优先于方向稿的冲突条款。
7
8
 
@@ -13,14 +13,6 @@ interface SshConnection {
13
13
  readonly key?: string;
14
14
  readonly proxyJump?: string;
15
15
  }
16
- /** One instance per Agent-owned driver; destroyed with its Agent/plugin owners. */
17
- declare class SshTargets {
18
- private readonly targets;
19
- register(label: string, connection: SshConnection): SshConnection;
20
- get(label: string): SshConnection | undefined;
21
- entries(): ReadonlyArray<readonly [string, SshConnection]>;
22
- clear(): void;
23
- }
24
16
  /** Shared by execution, probes and file/relay consumers. extraArgs is trusted
25
17
  * internal SSH argv (e.g. forwarding), never a model-provided shell string.
26
18
  * Identity assembly lives in ssh-argv.ts (the ONE policy — 2026-10-17 ruling);
@@ -172,6 +164,41 @@ interface HelperAssets {
172
164
  manifest: HelperManifest;
173
165
  }
174
166
  //#endregion
167
+ //#region src/remote/nonce-framing.d.ts
168
+ interface EnvDelta {
169
+ added: string[];
170
+ changed: string[];
171
+ removed: string[];
172
+ }
173
+ //#endregion
174
+ //#region src/remote/pty-session.d.ts
175
+ /** detached job 的完成结果(frame 或会话死亡时结算;与 dispatch 回执同构)。 */
176
+ interface PtyJobResult {
177
+ output: string;
178
+ outputStats?: StreamOutputStats;
179
+ exit: number | null;
180
+ cwd: string | null;
181
+ timedOut: boolean;
182
+ commandId: string;
183
+ envDelta?: EnvDelta;
184
+ }
185
+ /** P4/P5(2026-10-19)running job 句柄:byte-cursor 增量读 + P8 显式中断 + 完成时帧结算。 */
186
+ interface PtyRunningJob {
187
+ /** 账本键:与 jobId 同构(background 通道预传入 registry id;同步完成命令用同格式生成 id)。 */
188
+ commandId: string;
189
+ /** Byte-cursor incremental read over the command's merged output (tail-ring retention; lossy reports eviction). */
190
+ read: (fromByte: number) => {
191
+ text: string;
192
+ nextOffset: number;
193
+ lossy: boolean;
194
+ };
195
+ stats: () => OutputStats;
196
+ /** P8 两段式 ^C 中断(会话存活;trap-INT 走宽限 group-kill 兜底)。 */
197
+ interrupt: () => void;
198
+ /** Settles on the exit frame, or with exit null when the session dies. */
199
+ done: Promise<PtyJobResult>;
200
+ }
201
+ //#endregion
175
202
  //#region src/remote/process.d.ts
176
203
  declare const PROCESS_CLEANUP_BOUND_MS: number;
177
204
  interface ProcessOptions {
@@ -219,7 +246,6 @@ interface ProbeOptions {
219
246
  //#endregion
220
247
  //#region src/remote/roster.d.ts
221
248
  interface RosterOptions {
222
- byosshLabels?: readonly string[];
223
249
  /** 测试缝:替代 runOneShot 的容器扫描执行器。 */
224
250
  runner?: (argv: string[], opts?: OneShotOptions) => Promise<OneShotResult>;
225
251
  /** 测试缝:替代 ~/.ssh/config 读取。 */
@@ -242,12 +268,25 @@ interface RemoteCallResult {
242
268
  truncated?: number;
243
269
  outputStats?: StreamOutputStats;
244
270
  outputStatsUnavailable?: boolean;
245
- /** `byop:<label>` 调用面:本会话的 label(模型自选、即复用入口)。transport target 会话不带。 */
271
+ /** §5.2 回执字段序:session(+label)→ connection → commandId → state 字段(cwd/envDelta/ttlSec/exit)。 */
246
272
  session?: string;
247
- /** 引导/教学行(同 label 重复给 spawn 时的「可省略 spawn」提示等);无则省略。 */
273
+ label?: string;
274
+ connection?: string;
275
+ /** (byo-pty)/(byo-ssh) 来源标注(创建回执与 roster/card;native 回执省略)。 */
276
+ byoTag?: 'byo-pty' | 'byo-ssh';
277
+ commandId?: string;
278
+ envDelta?: EnvDelta;
279
+ /** 引导/教学行;无则省略。 */
248
280
  notice?: string;
249
281
  /** oneshot 监督路径的如实标注:`superd-run <ver> (<triple>)` 或 `posix-shim`(spec remote-rescope §5)。 */
250
282
  runner?: string;
283
+ /** P4/P5(2026-10-19):true = pty 命令仍在前台运行(回执 = handoff),ptyJob 随行供 job 通道接管。 */
284
+ running?: boolean;
285
+ ptyJob?: PtyRunningJob;
286
+ /** 本会话 idle TTL 剩余(秒);回执即状态快照(P2/P3:状态留在上下文里)。 */
287
+ ttlSec?: number;
288
+ /** 预热(创建形无 cmd)回执 = true。 */
289
+ created?: boolean;
251
290
  }
252
291
  interface RemoteAuditRecord {
253
292
  target: string;
@@ -274,16 +313,16 @@ interface RemoteDriverOptions {
274
313
  probeRunner?: ProbeOptions['runner'];
275
314
  /** 测试/验收缝:helper 资产来源(默认 lib 旁挂 helper-bin);显式 null 强制 shim 路径。 */
276
315
  helperAssetsFor?: () => HelperAssets | null;
277
- /** 测试缝:roster 扫描执行器(bare-name 解析复用)。 */
316
+ /** 测试缝:roster 扫描执行器(裸名解析复用)。 */
278
317
  rosterRunner?: RosterOptions['runner'];
279
- /** 测试缝:ssh config 读取(bare-name 解析复用)。 */
318
+ /** 测试缝:ssh config 读取(裸名解析复用)。 */
280
319
  sshConfigReader?: () => Promise<string>;
281
320
  }
282
- /** 双轨调度器(spec §七 Phase 2):参数校验 → 路由 → oneshot 子进程 / pty 会话池。 */
321
+ /** 双轨调度器:参数校验 → 目标语法(parseTargetForm)→ 统一 label 池 → oneshot 子进程 / pty 会话池。 */
283
322
  declare class RemoteDriver {
284
323
  private readonly opts;
285
- private readonly sshTargets;
286
324
  private readonly pool;
325
+ private readonly labels;
287
326
  private readonly hubOwner;
288
327
  private readonly hubProviders;
289
328
  private readonly processes;
@@ -294,14 +333,17 @@ declare class RemoteDriver {
294
333
  private helpers;
295
334
  private readonly runnerOf;
296
335
  private disposal;
336
+ private readonly ptyIdleTtlSec;
297
337
  constructor(opts?: RemoteDriverOptions);
298
338
  call(params: RemoteCallParams, callCtx?: {
299
339
  sessionKey?: string;
340
+ ptyBackground?: boolean;
341
+ commandId?: string;
300
342
  }): Promise<RemoteCallResult>;
301
- /** Native-first copy routing (spec: remote-native-shortcut): CLI peers run
302
- * their native CLI verbatim; only Hub↔local↔local stays on the staged tree
303
- * lane with verify/mkdir. Mixed pairs (Hub↔CLI peer) are refused: Hub has no
304
- * native CLI and the tree lane has no CLI options. */
343
+ /** 参数互斥矩阵(§2):spawn/ssh 是 BYO 入口(参数在场即 BYO),只与对应形态的 target 配对。 */
344
+ private validate;
345
+ private execute;
346
+ /** Native-first copy routing (spec: remote-native-shortcut) — unchanged by the workbench round. */
305
347
  copy(request: CopyRequest & {
306
348
  argv?: unknown;
307
349
  pullArgv?: unknown;
@@ -313,48 +355,80 @@ declare class RemoteDriver {
313
355
  sessionKey?: string;
314
356
  }): Promise<RsyncReceipt>;
315
357
  /** Only called from JobSpec.run: admission precedes local file reads and discovery. */
316
- start(input: RemoteInput, signal: AbortSignal): Promise<RemoteProcess>;
358
+ start(input: RemoteInput, signal: AbortSignal, callCtx?: {
359
+ sessionKey?: string;
360
+ }): Promise<RemoteProcess>;
317
361
  private startPrepared;
318
362
  private nativeProcess;
319
363
  /** Helper bootstrap is best-effort and sticky: any failure parks null for this driver
320
- * lifetime and the shim stays the path. First call to a target pays probe (+ upload). */
364
+ * lifetime and the shim stays the path. First call to a target pays probe (+ upload). */
321
365
  private ensureHelper;
322
366
  private helperExec;
323
367
  private own;
324
- /** Ruling 16/17:on-demand 探测 + 会话层,两行如实陈述。 */
325
- /**
326
- * Ruling P20 + PTY 候选表末位:裸名按名匹配——ssh config 字面 host → docker → incus(本地廉价扫描,
327
- * 撞名 ssh 优先),三段全不中再看池内活 PTY label,最后才是默认 ssh(交原生错误)。
328
- * 位置即优先级:现有三段一位不挪。选择器前缀的 target 不经此路径。
329
- */
330
- private resolveBareName;
331
- /** Ruling P19:roster = 注意力入口——本地廉价扫描(ssh config/docker ps/incus list + 池内活会话),零拨号。
332
- * 活的 pty 会话按调用方 agent session 过滤(2026-10-03 裁决):ssh/docker/incus 是**公共静态配置**,
333
- * 而活会话是**操作环境**——复用别的 agent 留下的 shell 等于继承未知状态,且两个 agent 各开一条线
334
- * 的代价可忽略。BYO-PTY 天然是活的,于是自然落进这个 scope,无需另立规则。 */
368
+ /** 现场采集机器面并 merge 进本 session 注册表(ssh → docker → incus → hub,迟到者加前缀)。错误逐段吞掉(roster 另行如实呈现)。 */
369
+ private refreshMachines;
370
+ /** 池寻址:命中即回;miss 现场采集一次再寻址(docker 容器名不经 roster 也可达)。 */
371
+ private resolvePoolEntry;
372
+ private planOf;
373
+ /** ssh:<name> 的池感知解析:BYO 身份 → 其 connection;否则按 config 别名/主机名。 */
374
+ private sshPlanFor;
375
+ /** BYO ssh 注册(v2:无 spec 对比——label 占用即拒;注册成功才认领)。返回实际名(label 或 s-id)。 */
376
+ private registerByoSsh;
377
+ /** PTY 会话创建(native/spawn 同一形状):上限 → label 认领 → 惰性会话(失败由 onDead 释放 label)。 */
378
+ private createSession;
379
+ private ttlMinutes;
380
+ /** connection 由 BYO ssh 身份建立 → card 面标 `(built on)`(与 roster 同词,R2 复核 P2-10)。 */
381
+ private isBuiltOn;
382
+ /** PTY 创建形唯一实现(execute 与 background 预建共用):spawn BYO / ssh BYO / native `<transport>:pty`。 */
383
+ private createPtyLane;
384
+ /** background PTY lane:会话先占位(不拨号)再进官方 jobs registry——首回执必须能寻址;
385
+ * registry 拒绝时把新建的会话拆掉(复用形的会话绝不拆)。返回 undefined = 走普通 oneshot job。 */
386
+ preparePtyLane(params: RemoteCallParams, callCtx?: {
387
+ sessionKey?: string;
388
+ }): Promise<{
389
+ input: RemoteInput;
390
+ session: string;
391
+ connection: string;
392
+ label?: string;
393
+ cleanup: () => void;
394
+ } | undefined>;
395
+ /** `pty:<id|label>` 寻址:先 id 后 label;miss 给重建形式。 */
396
+ private resolvePty;
397
+ /** §6 close:默认撞 detached job 报错(列杀法);force = 杀组+关闭(披露 killed)。幂等 not-found。 */
398
+ closePty(selector: string, sessionKey: string, force?: boolean): {
399
+ session: string;
400
+ connection: string;
401
+ closed: boolean;
402
+ reason?: string;
403
+ killed: string[];
404
+ message?: string;
405
+ };
406
+ /** job 通道收养回填(timeout handoff 时 registry id ≠ commandId,账本记录两者)。 */
407
+ attachPtyJob(commandId: string, jobId: string, sessionKey: string): void;
408
+ private dispatchPty;
409
+ /** 预热(创建形无 cmd)回执:§3——无 commandId/envDelta;timeout 忽略。 */
410
+ private warmReceipt;
411
+ /** session card 回执(`pty:<id|label>` 无 cmd):connection/state/cwd + 最近 20 条账本(不带输出尾,§9 Q7)。 */
412
+ private cardReceipt;
413
+ private oneshot;
414
+ private hubOneshot;
415
+ private hubOneshotProcess;
416
+ /** Ruling P19 + §2.5:roster = 注意力入口——本地扫描刷新统一池,零拨号;机器面公共,会话面 caller-scoped。 */
335
417
  roster(callCtx?: {
336
418
  sessionKey?: string;
337
419
  }): Promise<string>;
420
+ /** status probe(target 无 cmd):机器面 = probe + 该 connection 上的会话;pty selector = session card。 */
338
421
  status(target: string, callCtx?: {
339
422
  sessionKey?: string;
340
423
  }): Promise<string>;
341
- /** PTY 状态行:纯池内读取,零拨号(label 从来不是可拨目标)。 */
342
- private ptyStatus;
343
- /** Ruling 13:审计 best-effort——钩子抛错不得影响命令路径(成功被毒化成失败+双重审计)。 */
424
+ /** Ruling 13:审计 best-effort——钩子抛错不得影响命令路径。 */
344
425
  private audit;
345
- /** Registration never dials; response reveals labels only, not credentials. */
346
- registerSsh(target: string, connection: SshConnection): string;
347
- private byosshPlan;
348
- /** Single target resolver for later copy/rsync; BYO identities cannot be
349
- * independently re-resolved through the origin's alias table. */
426
+ /** Single target resolver for later copy/rsync; PTY sessions are not filesystem connections. */
350
427
  resolveConnectionTarget(target: string, callCtx?: {
351
428
  sessionKey?: string;
352
429
  }): Promise<TargetPlan>;
353
- private route;
354
- private execute;
355
- /** BYO-PTY 通道:label 即池键(agent 前缀之外),spawn 只在 label 尚不存在时被接受。
356
- * 三分支 —— 建(无会话)/ 复用(无 spawn,或有 spawn 且与创建来源相同)/ **冲突(有 spawn 且来源不同:不执行任何命令)**。 */
357
- private ptyCall;
430
+ /** P2/P3:回执即状态快照——idle TTL 剩余随每次 pty 回执带回。 */
431
+ private ptyTtl;
358
432
  hasHub(): boolean;
359
433
  private requireHub;
360
434
  private assertOpen;
@@ -367,13 +441,13 @@ interface RemoteInput {
367
441
  spawn?: string;
368
442
  ssh?: SshConnection;
369
443
  cmd?: string;
370
- script?: string;
444
+ scriptPath?: string;
371
445
  stdin?: string;
372
446
  mode?: 'oneshot' | 'pty';
373
447
  timeout?: number;
374
448
  }
375
449
  interface PreparedRemoteInput {
376
- target: string;
450
+ target?: string;
377
451
  spawn?: string;
378
452
  ssh?: SshConnection;
379
453
  cmd: string;
@@ -522,4 +596,4 @@ declare const _default: {
522
596
  apply: (ctx: Context, config: RemoteRowConfig) => (() => void);
523
597
  };
524
598
  //#endregion
525
- 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 };
599
+ 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, type StreamOutputStats, Utf16TailRing, apply, checkAbsolute, checkSelection, _default as default, inject, localFileEndpoint, name, readUtf8Tail, runFileWorker, runRsync, sshArgv, startBinaryProcess, startOneShot, startRemoteJob };