better-dsh 0.3.0-e → 0.3.0-g

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.
@@ -1,8 +1,429 @@
1
- import { t as Schema } from "../index-DTDXUe6m.js";
2
1
  import { Context } from "@deepseek-ai/cordis";
2
+ import { ToolRunContext } from "@deepseek-ai/dsh-tools";
3
+ import { Readable, Writable } from "node:stream";
4
+ import { NativeConfigSchema } from "@deepseek-ai/dsh-app-boot";
5
+ import { StandardSchemaV1 } from "../../third_party/schemastery/node_modules/@standard-schema/spec/dist/index.js";
6
+ import { JobId, JobRegistry } from "@deepseek-ai/dsh-jobs";
3
7
 
8
+ //#region src/remote/ssh-targets.d.ts
9
+ /** Origin-owned identity reference, never key contents or a persistent credential store. */
10
+ interface SshConnection {
11
+ readonly host: string;
12
+ readonly user?: string;
13
+ readonly port?: number;
14
+ readonly key?: string;
15
+ readonly proxyJump?: string;
16
+ }
17
+ /** One instance per Agent-owned driver; destroyed with its Agent/plugin owners. */
18
+ declare class SshTargets {
19
+ private readonly targets;
20
+ register(label: string, connection: SshConnection): SshConnection;
21
+ get(label: string): SshConnection | undefined;
22
+ entries(): ReadonlyArray<readonly [string, SshConnection]>;
23
+ clear(): void;
24
+ }
25
+ /** Shared by execution, probes and file/relay consumers. extraArgs is trusted
26
+ * internal SSH argv (e.g. forwarding), never a model-provided shell string. */
27
+ declare function sshArgv(connection: SshConnection, options?: {
28
+ tty?: boolean;
29
+ extraArgs?: readonly string[];
30
+ command?: string;
31
+ }): string[];
32
+ //#endregion
33
+ //#region src/remote/copy.d.ts
34
+ interface CopyRequest {
35
+ src: string;
36
+ dst: string;
37
+ verify?: boolean;
38
+ mkdir?: boolean;
39
+ }
40
+ interface TransferReceipt {
41
+ action: 'copy';
42
+ src: string;
43
+ dst: string;
44
+ verified: boolean;
45
+ sourceDigest?: string;
46
+ destinationDigest?: string;
47
+ bytes: number;
48
+ entries: number;
49
+ scratch?: string;
50
+ scope: 'transferred entries';
51
+ error?: string;
52
+ }
53
+ //#endregion
54
+ //#region src/remote/ssh-relay.d.ts
55
+ type SshBuilder = typeof sshArgv;
56
+ interface CommandResult {
57
+ exit: number | null;
58
+ stdout: string;
59
+ stderr: string;
60
+ outputTruncated: boolean;
61
+ }
62
+ interface RelayOptions {
63
+ ssh?: SshBuilder;
64
+ ports?: {
65
+ destination: number;
66
+ origin: number;
67
+ source: number;
68
+ };
69
+ }
70
+ interface Relay {
71
+ url: string;
72
+ /** Runs sender under a lease-owned remote supervisor, never downstream SSH. */
73
+ run(argv: string[]): Promise<CommandResult>;
74
+ }
75
+ declare function withSshRelay<T>(source: SshConnection, destination: SshConnection, targetPath: string, signal: AbortSignal, run: (relay: Relay) => Promise<T>, options?: RelayOptions): Promise<T>;
76
+ //#endregion
77
+ //#region src/remote/rsync.d.ts
78
+ interface RsyncRequest {
79
+ src: string;
80
+ dst: string;
81
+ dryRun?: boolean;
82
+ delete?: boolean;
83
+ excludes?: readonly string[];
84
+ preserve?: boolean;
85
+ }
86
+ interface RsyncEndpoint {
87
+ path: string;
88
+ connection?: SshConnection;
89
+ }
90
+ interface RsyncReceipt extends CommandResult {
91
+ action: 'rsync';
92
+ src: string;
93
+ dst: string;
94
+ dryRun: boolean;
95
+ delete: boolean;
96
+ preserve: boolean;
97
+ itemizedChanges: string[];
98
+ literalBytes?: number;
99
+ matchedBytes?: number;
100
+ sentBytes?: number;
101
+ receivedBytes?: number;
102
+ transferredBytes?: number;
103
+ }
104
+ declare function runRsync(request: RsyncRequest, source: RsyncEndpoint, destination: RsyncEndpoint, signal: AbortSignal, options?: RelayOptions): Promise<RsyncReceipt>;
105
+ //#endregion
106
+ //#region src/remote/target.d.ts
107
+ /** 解析后的传输计划:三种 CLI 传输之一。 */
108
+ type TargetPlan = {
109
+ kind: 'ssh';
110
+ host: string;
111
+ connection?: SshConnection;
112
+ } | {
113
+ kind: 'docker';
114
+ container: string;
115
+ } | {
116
+ kind: 'incus';
117
+ container: string;
118
+ };
119
+ //#endregion
120
+ //#region src/remote/process.d.ts
121
+ declare const PROCESS_CLEANUP_BOUND_MS: number;
122
+ interface ProcessOptions {
123
+ stdin?: string;
124
+ timeoutSec?: number;
125
+ cwd?: string;
126
+ /** Hub retains raw bytes; native transports retain decoded UTF16 units. */
127
+ unit?: 'bytes' | 'utf16';
128
+ onOutput?: () => void;
129
+ }
130
+ /** Real detached process. Completion includes group cleanup, even after its leader closes. */
131
+ declare function startBinaryProcess(argv: string[], options?: Pick<ProcessOptions, 'cwd' | 'timeoutSec'>): {
132
+ stdout: Readable;
133
+ stderr: Readable;
134
+ stdin: Writable;
135
+ cancel(): void;
136
+ done: RemoteProcess['done'];
137
+ diagnostic(): string | undefined;
138
+ };
139
+ /** Text adapter over the same owned process-group lifecycle as binary pipelines. */
140
+ declare function startOneShot(argv: string[], options?: ProcessOptions): RemoteProcess;
141
+ //#endregion
142
+ //#region src/remote/oneshot.d.ts
143
+ interface OneShotOptions {
144
+ stdin?: string;
145
+ timeoutSec?: number;
146
+ }
147
+ interface OneShotResult {
148
+ exit: number | null;
149
+ timedOut: boolean;
150
+ stdout: string;
151
+ stderr: string;
152
+ durationMs: number;
153
+ outputStats?: StreamOutputStats;
154
+ }
155
+ //#endregion
156
+ //#region src/remote/status.d.ts
157
+ interface ProbeOptions {
158
+ connectTimeoutSec?: number;
159
+ hardTimeoutSec?: number;
160
+ runner?: (argv: string[], opts?: OneShotOptions) => Promise<OneShotResult>;
161
+ }
162
+ //#endregion
163
+ //#region src/remote/roster.d.ts
164
+ interface RosterOptions {
165
+ byosshLabels?: readonly string[];
166
+ /** 测试缝:替代 runOneShot 的容器扫描执行器。 */
167
+ runner?: (argv: string[], opts?: OneShotOptions) => Promise<OneShotResult>;
168
+ /** 测试缝:替代 ~/.ssh/config 读取。 */
169
+ readSshConfig?: () => Promise<string>;
170
+ hardTimeoutSec?: number;
171
+ }
172
+ //#endregion
173
+ //#region src/remote/driver.d.ts
174
+ type RemoteCallParams = RemoteInput;
175
+ interface RemoteCallResult {
176
+ mode: 'oneshot' | 'pty';
177
+ target: string;
178
+ exit: number | null;
179
+ cwd: string | null;
180
+ timedOut: boolean;
181
+ reconnected: boolean;
182
+ stdout: string;
183
+ stderr?: string;
184
+ durationMs: number;
185
+ truncated?: number;
186
+ outputStats?: StreamOutputStats;
187
+ outputStatsUnavailable?: boolean;
188
+ /** `byop:<label>` 调用面:本会话的 label(模型自选、即复用入口)。transport target 会话不带。 */
189
+ session?: string;
190
+ /** 引导/教学行(同 label 重复给 spawn 时的「可省略 spawn」提示等);无则省略。 */
191
+ notice?: string;
192
+ }
193
+ interface RemoteAuditRecord {
194
+ target: string;
195
+ cmd: string;
196
+ cwd?: string;
197
+ exit?: number | null;
198
+ durationMs?: number;
199
+ error?: string;
200
+ }
201
+ interface RemoteDriverOptions {
202
+ /** Fixture transport seam; normal consumers use the canonical native SSH builder. */
203
+ rsyncSshArgv?: SshBuilder;
204
+ getHub?: () => HubRemoteTransport | undefined;
205
+ execTimeoutSec?: number;
206
+ idleTtlSec?: number;
207
+ maxOutputChars?: number;
208
+ onAudit?: (r: RemoteAuditRecord) => void;
209
+ oneshotArgvFor?: (plan: TargetPlan, cmd: string) => string[];
210
+ ptyArgvFor?: (plan: TargetPlan) => string[];
211
+ spawnArgvFor?: (spawnCommand: string) => string[];
212
+ probeRunner?: ProbeOptions['runner'];
213
+ /** 测试缝:roster 扫描执行器(bare-name 解析复用)。 */
214
+ rosterRunner?: RosterOptions['runner'];
215
+ /** 测试缝:ssh config 读取(bare-name 解析复用)。 */
216
+ sshConfigReader?: () => Promise<string>;
217
+ }
218
+ /** 双轨调度器(spec §七 Phase 2):参数校验 → 路由 → oneshot 子进程 / pty 会话池。 */
219
+ declare class RemoteDriver {
220
+ private readonly opts;
221
+ private readonly sshTargets;
222
+ private readonly pool;
223
+ private readonly hubOwner;
224
+ private readonly hubProviders;
225
+ private readonly processes;
226
+ private readonly starting;
227
+ private readonly fileAbort;
228
+ private disposed;
229
+ private disposal;
230
+ constructor(opts?: RemoteDriverOptions);
231
+ call(params: RemoteCallParams, callCtx?: {
232
+ sessionKey?: string;
233
+ }): Promise<RemoteCallResult>;
234
+ copy(request: CopyRequest, signal: AbortSignal, callCtx?: {
235
+ sessionKey?: string;
236
+ }): Promise<TransferReceipt>;
237
+ rsync(request: RsyncRequest, signal: AbortSignal, callCtx?: {
238
+ sessionKey?: string;
239
+ }): Promise<RsyncReceipt>;
240
+ /** Only called from JobSpec.run: admission precedes local file reads and discovery. */
241
+ start(input: RemoteInput, signal: AbortSignal): Promise<RemoteProcess>;
242
+ private startPrepared;
243
+ private nativeProcess;
244
+ private own;
245
+ /** Ruling 16/17:on-demand 探测 + 会话层,两行如实陈述。 */
246
+ /**
247
+ * Ruling P20 + PTY 候选表末位:裸名按名匹配——ssh config 字面 host → docker → incus(本地廉价扫描,
248
+ * 撞名 ssh 优先),三段全不中再看池内活 PTY label,最后才是默认 ssh(交原生错误)。
249
+ * 位置即优先级:现有三段一位不挪。选择器前缀的 target 不经此路径。
250
+ */
251
+ private resolveBareName;
252
+ /** Ruling P19:roster = 注意力入口——本地廉价扫描(ssh config/docker ps/incus list + 池内活会话),零拨号。
253
+ * 活的 pty 会话按调用方 agent session 过滤(2026-10-03 裁决):ssh/docker/incus 是**公共静态配置**,
254
+ * 而活会话是**操作环境**——复用别的 agent 留下的 shell 等于继承未知状态,且两个 agent 各开一条线
255
+ * 的代价可忽略。BYO-PTY 天然是活的,于是自然落进这个 scope,无需另立规则。 */
256
+ roster(callCtx?: {
257
+ sessionKey?: string;
258
+ }): Promise<string>;
259
+ status(target: string, callCtx?: {
260
+ sessionKey?: string;
261
+ }): Promise<string>;
262
+ /** PTY 状态行:纯池内读取,零拨号(label 从来不是可拨目标)。 */
263
+ private ptyStatus;
264
+ /** Ruling 13:审计 best-effort——钩子抛错不得影响命令路径(成功被毒化成失败+双重审计)。 */
265
+ private audit;
266
+ /** Registration never dials; response reveals labels only, not credentials. */
267
+ registerSsh(target: string, connection: SshConnection): string;
268
+ private byosshPlan;
269
+ /** Single target resolver for later copy/rsync; BYO identities cannot be
270
+ * independently re-resolved through the origin's alias table. */
271
+ resolveConnectionTarget(target: string, callCtx?: {
272
+ sessionKey?: string;
273
+ }): Promise<TargetPlan>;
274
+ private route;
275
+ private execute;
276
+ /** BYO-PTY 通道:label 即池键(agent 前缀之外),spawn 只在 label 尚不存在时被接受。
277
+ * 三分支 —— 建(无会话)/ 复用(无 spawn,或有 spawn 且与创建来源相同)/ **冲突(有 spawn 且来源不同:不执行任何命令)**。 */
278
+ private ptyCall;
279
+ hasHub(): boolean;
280
+ private requireHub;
281
+ private assertOpen;
282
+ dispose(): Promise<void>;
283
+ }
284
+ //#endregion
285
+ //#region src/remote/hub-contract.d.ts
286
+ interface RemoteInput {
287
+ target?: string;
288
+ spawn?: string;
289
+ ssh?: SshConnection;
290
+ cmd?: string;
291
+ script?: string;
292
+ stdin?: string;
293
+ mode?: 'oneshot' | 'pty';
294
+ timeout?: number;
295
+ }
296
+ interface PreparedRemoteInput {
297
+ target: string;
298
+ spawn?: string;
299
+ ssh?: SshConnection;
300
+ cmd: string;
301
+ stdin?: string;
302
+ mode?: 'oneshot' | 'pty';
303
+ timeout?: number;
304
+ }
305
+ /** Counters exclude diagnostic banners. dropped is ring eviction; total-returned is all omitted output. */
306
+ type OutputStats = {
307
+ unit: 'utf16' | 'bytes';
308
+ total: number;
309
+ retained: number;
310
+ dropped: number;
311
+ returned: number;
312
+ retentionLimit: number;
313
+ };
314
+ type StreamOutputStats = {
315
+ stdout: OutputStats;
316
+ stderr?: OutputStats;
317
+ };
318
+ interface RemoteProcess {
319
+ cancel(reason?: string): void;
320
+ done: Promise<{
321
+ exit: number | null;
322
+ timedOut: boolean;
323
+ durationMs: number;
324
+ cancelled?: boolean;
325
+ }>;
326
+ /** diagnostic is executor-generated text, not process output; excluded from byte cursor and counters. */
327
+ read(channel: 'stdout' | 'stderr', fromByte: number): {
328
+ text: string;
329
+ nextOffset: number;
330
+ lossy: boolean;
331
+ stats?: OutputStats;
332
+ diagnostic?: string;
333
+ };
334
+ }
335
+ interface BinaryFileEndpoint {
336
+ exportTree(path: string, signal: AbortSignal): Promise<NodeJS.ReadableStream>;
337
+ importTree(path: string, source: NodeJS.ReadableStream, options: {
338
+ mkdir: boolean;
339
+ signal: AbortSignal;
340
+ }): Promise<void>;
341
+ digest(path: string, signal: AbortSignal, selection?: readonly string[]): Promise<{
342
+ sha256: string;
343
+ bytes: number;
344
+ entries: number;
345
+ }>;
346
+ }
347
+ interface HubTarget {
348
+ id: string;
349
+ label: string;
350
+ execEnabled: boolean;
351
+ }
352
+ interface HubRemoteTransport {
353
+ protocol: 1;
354
+ listTargets(): readonly HubTarget[];
355
+ start(machine: string, input: PreparedRemoteInput, owner: string): Promise<RemoteProcess>;
356
+ pty(machine: string, cmd: string, owner: string, options: {
357
+ stdin?: string;
358
+ timeout?: number;
359
+ }): Promise<RemoteCallResult>;
360
+ fileEndpoint(machine: string): BinaryFileEndpoint;
361
+ releaseOwner(owner: string): Promise<void>;
362
+ }
363
+ //#endregion
364
+ //#region src/remote/output-ring.d.ts
365
+ /** Byte-addressed decoded output: mid-codepoint cursors skip forward and explicitly report loss. */
366
+ declare function readUtf8Tail(bytes: Buffer, totalBytes: number, fromByte: number): {
367
+ text: string;
368
+ nextOffset: number;
369
+ lossy: boolean;
370
+ };
371
+ /** Native/PTY retention is UTF16 units; cursor offsets remain real UTF8 bytes. Input is decoded text. */
372
+ declare class Utf16TailRing {
373
+ readonly capacity: number;
374
+ text: string;
375
+ total: number;
376
+ private totalBytes;
377
+ constructor(capacity?: number);
378
+ push(text: string): void;
379
+ stats(returned?: number): OutputStats;
380
+ read(fromByte: number): ReturnType<typeof readUtf8Tail>;
381
+ }
382
+ /** Raw byte retention for Hub oneshot. Tail/read starts skip partial UTF8 prefixes, never invent replacement characters. */
383
+ declare class ByteTailRing {
384
+ readonly capacity: number;
385
+ total: number;
386
+ private chunks;
387
+ private retained;
388
+ constructor(capacity?: number);
389
+ push(chunk: Buffer): void;
390
+ tail(maxBytes?: number): Buffer;
391
+ stats(returned?: number): OutputStats;
392
+ read(fromByte: number): ReturnType<typeof readUtf8Tail>;
393
+ }
394
+ //#endregion
395
+ //#region src/remote/jobs.d.ts
396
+ declare module '@deepseek-ai/dsh-jobs' {
397
+ interface JobKindMap {
398
+ remote: 'remote';
399
+ }
400
+ }
401
+ /** No preparation or discovery before the official registry's admission. */
402
+ declare function startRemoteJob(registry: JobRegistry, input: RemoteInput, exec: ToolRunContext, driver: RemoteDriver): JobId;
403
+ //#endregion
404
+ //#region src/remote/archive.d.ts
405
+ declare const FILE_FRAME_BYTES: number;
406
+ declare const FILE_MAX_ENTRIES = 10000;
407
+ declare const FILE_MAX_METADATA: number;
408
+ declare function checkAbsolute(p: string): void;
409
+ declare function checkSelection(selection: readonly string[]): void;
410
+ /** Internal worker ownership hooks, not a second endpoint contract. */
411
+ interface LocalFileResources {
412
+ receiveRoot?: string;
413
+ temporary?(path: string, active: boolean): Promise<void>;
414
+ }
415
+ declare function localFileEndpoint(resources?: LocalFileResources): BinaryFileEndpoint;
416
+ //#endregion
417
+ //#region src/remote/file-worker.d.ts
418
+ declare function runFileWorker(request: {
419
+ action: 'export' | 'import' | 'digest';
420
+ path: string;
421
+ mkdir: boolean;
422
+ root: string;
423
+ selected: boolean;
424
+ }): Promise<void>;
425
+ //#endregion
4
426
  //#region src/remote/plugin.d.ts
5
-
6
427
  declare const name = "dashr-remote";
7
428
  declare const inject: string[];
8
429
  /** 运行参数旋钮(Ruling P18):无别名表面——容器一律显式 'docker:' / 'incus:' 前缀。 */
@@ -11,14 +432,15 @@ interface RemoteRowConfig {
11
432
  idleTtlSec: number;
12
433
  maxOutputChars: number;
13
434
  }
14
- declare const Config: Schema<RemoteRowConfig>;
435
+ type RemoteConfigValidator = ((value?: unknown) => RemoteRowConfig) & StandardSchemaV1<unknown, RemoteRowConfig> & NativeConfigSchema;
436
+ declare const Config: RemoteConfigValidator;
15
437
  /** MUST stay an arrow(RM0 plugin.ts 同注:function 声明会被 cordis 当构造器 new 掉,返回的 disposer 丢失)。 */
16
438
  declare const apply: (ctx: Context, config: RemoteRowConfig) => (() => void);
17
439
  declare const _default: {
18
440
  name: string;
19
441
  inject: string[];
20
- Config: Schema<RemoteRowConfig>;
442
+ Config: RemoteConfigValidator;
21
443
  apply: (ctx: Context, config: RemoteRowConfig) => (() => void);
22
444
  };
23
445
  //#endregion
24
- export { Config, RemoteRowConfig, apply, _default as default, inject, name };
446
+ 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, withSshRelay };