dshb-exec-ssh 0.0.1

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.
@@ -0,0 +1,3328 @@
1
+ import { i as Dict, n as Context, r as StandardSchemaV1, t as Service } from "./index-CDfaZYyK.js";
2
+ import { SshExecutor } from "./executor.js";
3
+ import { Readable, Writable } from "node:stream";
4
+ //#region ../../node_modules/@deepseek-ai/cosmokit/lib/types/types.d.ts
5
+ declare function isArrayBufferLike(value: any): value is ArrayBufferLike;
6
+ declare function isArrayBufferSource(value: any): value is Binary.Source;
7
+ /** Binary source detection and base64/hex conversion helpers. */
8
+ declare namespace Binary {
9
+ type Source<T extends ArrayBufferLike = ArrayBufferLike> = T | ArrayBufferView<T>;
10
+ const is: typeof isArrayBufferLike;
11
+ const isSource: typeof isArrayBufferSource;
12
+ function fromSource<T extends ArrayBufferLike>(source: Source<T>): T;
13
+ function toBase64(source: Source): string;
14
+ function fromBase64(source: string): ArrayBuffer | Uint8Array<ArrayBuffer>;
15
+ function toHex(source: Source): string;
16
+ function fromHex(source: string): ArrayBuffer;
17
+ }
18
+ //#endregion
19
+ //#region ../../node_modules/@deepseek-ai/schemastery/lib/types/index.d.ts
20
+ declare const kSchema: unique symbol;
21
+ declare global {
22
+ namespace Schemastery {
23
+ /** Convert primitive constructors, constants, and existing schemas into a schema type. */
24
+ type From<X> = X extends string | number | boolean ? Schema<X> : X extends Schema ? X : X extends typeof String ? Schema<string> : X extends typeof Number ? Schema<number> : X extends typeof Boolean ? Schema<boolean> : X extends typeof Function ? Schema<Function, (...args: any[]) => any> : X extends Constructor<infer S> ? Schema<S> : never;
25
+ type TypeS1<X> = X extends Schema<infer S, unknown> ? S : never;
26
+ type Inverse<X> = X extends Schema<any, infer Y> ? (arg: Y) => void : never;
27
+ /** Input type accepted by a schema-like value. */
28
+ type TypeS<X> = TypeS1<From<X>>;
29
+ /** Output type returned by a schema-like value after validation. */
30
+ type TypeT<X> = ReturnType<From<X>>;
31
+ /** Resolver callback used by custom schema types registered with `Schema.extend()`. */
32
+ type Resolve = (data: any, schema: Schema, options: Options, strict?: boolean) => [any, any?];
33
+ /** Input type accepted by one schema in an intersection. */
34
+ type IntersectS<X> = From<X> extends Schema<infer S, unknown> ? S : never;
35
+ /** Output type returned by one schema in an intersection. */
36
+ type IntersectT<X> = Inverse<From<X>> extends ((arg: infer T) => void) ? T : never;
37
+ type TupleS<X extends readonly any[]> = X extends readonly [infer L, ...infer R] ? [TypeS<L>?, ...TupleS<R>] : any[];
38
+ type TupleT<X extends readonly any[]> = X extends readonly [infer L, ...infer R] ? [TypeT<L>?, ...TupleT<R>] : any[];
39
+ type ObjectS<X extends Dict> = { [K in keyof X]?: TypeS<X[K]> | null; } & Dict;
40
+ type ObjectT<X extends Dict> = { [K in keyof X]: TypeT<X[K]>; } & Dict;
41
+ type Constructor<T = any> = new (...args: any[]) => T;
42
+ /** Static constructor and factory methods exposed by the default `Schema` export. */
43
+ interface Static {
44
+ <T = any>(options: Partial<Schema<T>>): Schema<T>;
45
+ new <T = any>(options: Partial<Schema<T>>): Schema<T>;
46
+ prototype: Schema;
47
+ /** Validate a value against a schema node and return `[output, adaptedInput?]`. */
48
+ resolve: Resolve;
49
+ /** Infer a schema from a primitive value, constructor, or existing schema. */
50
+ from<X = any>(source?: X): From<X>;
51
+ /** Register a resolver for a custom schema `type`. */
52
+ extend(type: string, resolve: Resolve): void;
53
+ /** Accept any value without validation. */
54
+ any<T = any>(): Schema<T>;
55
+ /** Accept only nullable input. */
56
+ never(): Schema<never>;
57
+ /** Accept exactly one constant value. */
58
+ const<const T>(value: T): Schema<T>;
59
+ /** Accept strings, with optional metadata constraints added by instance methods. */
60
+ string(): Schema<string>;
61
+ /** Accept numbers, with optional range and step constraints. */
62
+ number(): Schema<number>;
63
+ /** Accept non-negative integer numbers. */
64
+ natural(): Schema<number>;
65
+ /** Accept a number between 0 and 1 and mark it as a slider. */
66
+ percent(): Schema<number>;
67
+ /** Accept booleans. */
68
+ boolean(): Schema<boolean>;
69
+ /** Accept `Date` instances or parse datetime strings into `Date` objects. */
70
+ date(): Schema<string | Date, Date>;
71
+ /** Accept `RegExp` instances or parse strings into regular expressions. */
72
+ regExp(flag?: string): Schema<string | RegExp, RegExp>;
73
+ /** Accept binary sources and normalize them to `ArrayBufferLike`. */
74
+ arrayBuffer(): Schema<Binary.Source, ArrayBufferLike>;
75
+ arrayBuffer(encoding: 'hex' | 'base64'): Schema<Binary.Source | string, ArrayBufferLike>;
76
+ /** Accept a numeric bitset or string keys and normalize to a number. */
77
+ bitset<K extends string>(bits: Partial<Record<K, number>>): Schema<number | readonly K[], number>;
78
+ /** Accept functions. */
79
+ function(): Schema<Function, (...args: any[]) => any>;
80
+ /** Accept instances of a constructor or objects whose constructor name matches. */
81
+ is(constructor: string): Schema;
82
+ is<T>(constructor: Constructor<T>): Schema<T>;
83
+ /** Accept arrays whose elements match `inner`. */
84
+ array<X>(inner: X): Schema<TypeS<X>[], TypeT<X>[]>;
85
+ /** Accept plain objects with values matching `inner` and optional key schema. */
86
+ dict<X, Y extends Schema<any, string> = Schema<string>>(inner: X, sKey?: Y): Schema<Dict<TypeS<X>, TypeS<Y>>, Dict<TypeT<X>, TypeT<Y>>>;
87
+ /** Accept tuple arrays where each index matches the corresponding schema. */
88
+ tuple<const X extends readonly any[]>(list: X): Schema<TupleS<X>, TupleT<X>>;
89
+ /** Accept plain objects whose declared properties match the schema dictionary. */
90
+ object<X extends Dict>(dict: X): Schema<ObjectS<X>, ObjectT<X>>;
91
+ /** Accept values matching at least one schema in `list`. */
92
+ union<const X>(list: readonly X[]): Schema<TypeS<X>, TypeT<X>>;
93
+ /** Accept values matching every schema in `list`, merging object outputs. */
94
+ intersect<const X>(list: readonly X[]): Schema<IntersectS<X>, IntersectT<X>>;
95
+ /** Validate with `inner`, then convert the result with `callback`. */
96
+ transform<X, T>(inner: X, callback: (value: TypeS<X>, options: Schemastery.Options) => T, preserve?: boolean): Schema<TypeS<X>, T>;
97
+ /** Defer construction of a recursive schema until validation or serialization. */
98
+ lazy<X extends Schema>(callback: () => X): X;
99
+ ValidationError: typeof ValidationError;
100
+ }
101
+ /** Runtime validation options shared by all schema calls. */
102
+ interface Options {
103
+ /** Remove invalid object properties instead of throwing when possible. */
104
+ autofix?: boolean;
105
+ /** Skip validation for selected values and schema nodes. */
106
+ ignore?(data: any, schema: Schema): boolean;
107
+ /** Path used to format nested validation errors. */
108
+ path?: (keyof any)[];
109
+ }
110
+ /** UI and validation metadata attached by schema builder methods. */
111
+ interface Meta<T = any> {
112
+ default?: T extends {} ? Partial<T> : T;
113
+ required?: boolean;
114
+ disabled?: boolean;
115
+ collapse?: boolean;
116
+ badges?: {
117
+ text: string;
118
+ type: string;
119
+ }[];
120
+ hidden?: boolean;
121
+ loose?: boolean;
122
+ role?: string;
123
+ extra?: any;
124
+ link?: string;
125
+ description?: string | Dict<string>;
126
+ comment?: string;
127
+ pattern?: {
128
+ source: string;
129
+ flags?: string;
130
+ };
131
+ max?: number;
132
+ min?: number;
133
+ step?: number;
134
+ }
135
+ }
136
+ /** Callable schema instance that validates input and returns normalized output. */
137
+ interface Schemastery<S = any, T = S> {
138
+ (data?: S | null, options?: Schemastery.Options): T;
139
+ new (data?: S | null, options?: Schemastery.Options): T;
140
+ [kSchema]: true;
141
+ uid: number;
142
+ meta: Schemastery.Meta<T>;
143
+ type: string;
144
+ sKey?: Schema;
145
+ inner?: Schema;
146
+ list?: Schema[];
147
+ dict?: Dict<Schema>;
148
+ bits?: Dict<number>;
149
+ callback?: Function;
150
+ constructor?: string | Function;
151
+ builder?: Function;
152
+ value?: T;
153
+ refs?: Dict<Schema>;
154
+ preserve?: boolean;
155
+ '~standard': StandardSchemaV1.Props;
156
+ /** Format this schema as a compact TypeScript-like type string. */
157
+ toString(inline?: boolean): string;
158
+ /** Serialize this schema, preserving shared and recursive references. */
159
+ toJSON(): Schema<S, T>;
160
+ /** Mark nullable input as invalid unless a default supplies a fallback. */
161
+ required(value?: boolean): Schema<S, T>;
162
+ /** Hide this schema node from UI renderers. */
163
+ hidden(value?: boolean): Schema<S, T>;
164
+ /** Return the default value instead of throwing when validation fails. */
165
+ loose(value?: boolean): Schema<S, T>;
166
+ /** Attach a renderer role and optional role-specific metadata. */
167
+ role(text: string, extra?: any): Schema<S, T>;
168
+ /** Attach an external documentation link. */
169
+ link(link: string): Schema<S, T>;
170
+ /** Set the fallback value used for nullable input. */
171
+ default(value: T): Schema<S, T>;
172
+ /** Attach an auxiliary comment for documentation or form UIs. */
173
+ comment(text: string): Schema<S, T>;
174
+ /** Attach a localized or plain description for documentation or form UIs. */
175
+ description(text: string): Schema<S, T>;
176
+ /** Mark this schema node as disabled for form UIs. */
177
+ disabled(value?: boolean): Schema<S, T>;
178
+ /** Request collapsed rendering for nested form UIs. */
179
+ collapse(value?: boolean): Schema<S, T>;
180
+ /** Add a deprecated badge to this schema node. */
181
+ deprecated(): Schema<S, T>;
182
+ /** Add an experimental badge to this schema node. */
183
+ experimental(): Schema<S, T>;
184
+ /** Require strings to match a regular expression. */
185
+ pattern(regexp: RegExp): Schema<S, T>;
186
+ /** Set an inclusive maximum for numbers or collection lengths. */
187
+ max(value: number): Schema<S, T>;
188
+ /** Set an inclusive minimum for numbers or collection lengths. */
189
+ min(value: number): Schema<S, T>;
190
+ /** Set the numeric increment constraint. */
191
+ step(value: number): Schema<S, T>;
192
+ /** Add or replace an object property schema. */
193
+ set(key: string, value: Schema): Schema<S, T>;
194
+ /** Append a tuple, union, or intersection member schema. */
195
+ push(value: Schema): Schema<S, T>;
196
+ /** Remove values equal to schema defaults from normalized output. */
197
+ simplify(value?: any): any;
198
+ /** Return a schema clone with descriptions merged from locale messages. */
199
+ i18n(messages: Dict): Schema<S, T>;
200
+ /** Attach arbitrary metadata consumed by form renderers and downstream tools. */
201
+ extra<K extends keyof Schemastery.Meta>(key: K, value: Schemastery.Meta[K]): Schema<S, T>;
202
+ }
203
+ }
204
+ declare class ValidationError extends TypeError {
205
+ options: Schemastery.Options;
206
+ name: string;
207
+ constructor(message: string, options: Schemastery.Options);
208
+ static is(error: any): error is ValidationError;
209
+ }
210
+ type Schema<S = any, T = S> = Schemastery<S, T>;
211
+ declare const Schema: Schemastery.Static;
212
+ //#endregion
213
+ //#region ../../node_modules/@deepseek-ai/dsh-settings/lib/types/redact.d.ts
214
+ /** One schema-declared secret position inside a redacted value. */
215
+ interface RedactedSecret {
216
+ /** Path from the section root to the removed field (concrete dict keys and array indexes included). */
217
+ path: string[];
218
+ /** Whether the field held a value before redaction. */
219
+ set: boolean;
220
+ }
221
+ //#endregion
222
+ //#region ../../node_modules/@deepseek-ai/dsh-brand/lib/types/index.d.ts
223
+ /**
224
+ * The `Branded<B>` nominal-typing primitive — a type-only utility (no runtime
225
+ * code, no harness-package dependency) shared by every package that owns a
226
+ * cross-boundary id.
227
+ *
228
+ * A brand makes structurally-identical strings non-interchangeable at the type
229
+ * level: a `SessionId` cannot be passed where a `CallId` is expected, even
230
+ * though both are plain strings at runtime. Construction goes through a per-id
231
+ * factory in the OWNING package (a plain cast inside — zero runtime cost);
232
+ * comparison, logging, and serialization all behave as ordinary strings.
233
+ *
234
+ * Policy: a package brands the ids it owns — `CallId` in dsh-llm (tool-call
235
+ * correlation), the shared agent/session `SessionId` in dsh-session, and
236
+ * `JobId` in dsh-jobs. Branding is for ids that cross package boundaries and
237
+ * could plausibly be confused; not every string needs a brand.
238
+ * This package owns ONLY the primitive — no concrete id, no runtime code beyond
239
+ * the (erased) type — so the brand vocabulary stays dependency-free and a
240
+ * package can brand its ids without depending on an unrelated capability
241
+ * package.
242
+ *
243
+ * @module @deepseek-ai/dsh-brand
244
+ */
245
+ declare const BRAND: unique symbol;
246
+ /** A string carrying a compile-time-only brand `B`. */
247
+ type Branded<B extends string> = string & {
248
+ readonly [BRAND]: B;
249
+ };
250
+ //#endregion
251
+ //#region ../../node_modules/@deepseek-ai/dsh-settings/lib/types/types.d.ts
252
+ /** Nominal id of one registered settings namespace. */
253
+ type SettingsNamespace = Branded<'SettingsNamespace'>;
254
+ /** Origin of one committed settings change. */
255
+ type SettingsUpdateSource = 'update' | 'provider';
256
+ declare module '@deepseek-ai/cordis' {
257
+ interface Events {
258
+ /**
259
+ * Committed change to one registered namespace's resolved value. Emitted
260
+ * after the provider persisted (for `update`) or published (`provider`)
261
+ * the change; never emitted when the resolved value is deep-equal.
262
+ * Listener failures are contained and logged — a sync throw and an async
263
+ * rejection alike — except `INVARIANT`-coded failures, which rethrow
264
+ * after every listener ran; that rethrow reaches the emitter only from
265
+ * synchronous listeners, so invariant checks on this event must not be
266
+ * async functions.
267
+ * @param ns - the namespace whose resolved value changed.
268
+ * @param next - the new resolved value.
269
+ * @param prev - the previous resolved value.
270
+ * @param source - whether the change entered through `update()` or the provider.
271
+ * @mode emit
272
+ */
273
+ 'settings/updated'(ns: SettingsNamespace, next: unknown, prev: unknown, source: SettingsUpdateSource): void;
274
+ /**
275
+ * One registered namespace's RAW user section changed, whether or not the
276
+ * resolved value did. `settings/updated` is the consumer-facing event and
277
+ * stays deep-equal-gated; this one exists for configuration surfaces,
278
+ * which must learn that a field went from inherited to overridden (same
279
+ * resolved value, different meaning) and that their held revision is
280
+ * stale. Listener containment matches `settings/updated`.
281
+ * @param ns - the namespace whose stored section changed.
282
+ * @param revision - the namespace's new revision.
283
+ * @mode emit
284
+ */
285
+ 'settings/document-updated'(ns: SettingsNamespace, revision: number): void;
286
+ }
287
+ }
288
+ //#endregion
289
+ //#region ../../node_modules/@deepseek-ai/dsh-settings/lib/types/index.d.ts
290
+ /** When a namespace's changes take effect for its owner. */
291
+ type SettingsApplies = 'live' | 'restart';
292
+ /** Registration options beyond the namespace schema. */
293
+ interface SettingsRegisterOptions<T> {
294
+ /** Composition-layer values resolved below the user layer (entry-config subset). */
295
+ base?: Partial<T>;
296
+ /** Owner's effect timing, surfaced to configuration UIs; defaults to `live`. */
297
+ applies?: SettingsApplies;
298
+ /**
299
+ * Reject a resolved section the owner could not act on, for constraints its
300
+ * schema cannot express — a cross-field requirement, or one field's validity
301
+ * depending on another's. Throwing here refuses the *write* that produced the
302
+ * value, so a caller learns at `update`/`replace`/`mutate` instead of storing
303
+ * something that would silently disable the owner.
304
+ *
305
+ * Kept separate from the schema because the schema is also what a
306
+ * configuration surface renders and what an absent section resolves through;
307
+ * folding a cross-field check into it would change both.
308
+ *
309
+ * Once the owner is registered, a stored section that fails this keeps the
310
+ * namespace's last good value and warns, exactly as a schema failure does,
311
+ * so an externally edited document cannot strand a running owner. At
312
+ * registration there is no last good value yet, so a stored section that
313
+ * already fails rejects the registration itself — again exactly as a schema
314
+ * failure does.
315
+ * @param value - the resolved section, schema-valid by construction.
316
+ */
317
+ validate?: (value: T) => void;
318
+ }
319
+ /** One registered namespace as surfaced to configuration UIs. */
320
+ interface SettingsDescriptor {
321
+ /** The registered namespace. */
322
+ ns: SettingsNamespace;
323
+ /** Serialized schemastery schema (`schema.toJSON()`). */
324
+ schema: unknown;
325
+ /** Current resolved value. */
326
+ value: unknown;
327
+ /**
328
+ * Monotonic revision of the raw user section this descriptor was read at.
329
+ * Send it back as `expectedRevision` on a write to refuse a stale one.
330
+ */
331
+ revision: number;
332
+ /** Registrant's composition `base` layer (detached), when one was declared. */
333
+ base?: unknown;
334
+ /**
335
+ * Raw user section from the stored document (detached), when one exists and
336
+ * is well-formed; a field's presence here is what marks it user-overridden.
337
+ */
338
+ user?: unknown;
339
+ /** Owner's declared effect timing. */
340
+ applies: SettingsApplies;
341
+ /** Schema-declared secret positions; present only under `redactSecrets`. */
342
+ secrets?: RedactedSecret[];
343
+ }
344
+ /** Options for {@link SettingsProvider.describe}. */
345
+ interface SettingsDescribeOptions {
346
+ /**
347
+ * Strip `role('secret')` fields from `value`/`base`/`user` and enumerate
348
+ * them in each descriptor's `secrets`. Every wire surface MUST pass this;
349
+ * the verbatim default exists for same-process configuration UIs only.
350
+ */
351
+ redactSecrets?: boolean;
352
+ }
353
+ /** Owner-facing handle for one registered namespace. */
354
+ interface SettingsScope<T> {
355
+ /** Current resolved value: schema defaults, then `base`, then the user layer. */
356
+ get(): T;
357
+ /**
358
+ * Observe committed changes to this namespace's resolved value. Invocations
359
+ * of one callback run asynchronously, one at a time, in commit order; a
360
+ * rejection is contained and logged like a sync throw. After the disposer
361
+ * returns, no further invocation starts — one already queued is skipped;
362
+ * one already started still settles, and service disposal waits for it.
363
+ * @param callback - invoked after each commit with the next and previous values.
364
+ * @returns the disposer removing this observer.
365
+ */
366
+ watch(callback: (next: T, prev: T) => void | Promise<void>): () => void;
367
+ /**
368
+ * Merge a partial patch into this namespace's user layer and persist it.
369
+ * @param patch - plain-object patch over the user section; JSON-compatible data
370
+ * only (non-JSON values reject with their path before anything persists).
371
+ */
372
+ update(patch: object): Promise<void>;
373
+ /**
374
+ * Replace this namespace's user section wholesale; absent keys re-inherit
375
+ * the composition `base` and schema defaults (`replace({})` resets all).
376
+ * @param section - the complete next user section; JSON-compatible data only,
377
+ * as for {@link update}.
378
+ */
379
+ replace(section: object): Promise<void>;
380
+ }
381
+ declare module '@deepseek-ai/cordis' {
382
+ interface Context {
383
+ settings: SettingsProvider;
384
+ }
385
+ }
386
+ /**
387
+ * One path-addressed edit to a namespace's user section. Path mutation exists
388
+ * for a caller holding an INCOMPLETE view of the section — a configuration UI
389
+ * reads the redacted descriptor, which by construction never received the
390
+ * `role('secret')` fields. Such a caller can name the field it means without
391
+ * restating the section: a wholesale `replace` rebuilt from a redacted
392
+ * document silently deletes every secret the wire never returned.
393
+ */
394
+ type SettingsPathOp = {
395
+ op: 'set';
396
+ path: readonly string[];
397
+ value: unknown;
398
+ } | {
399
+ op: 'unset';
400
+ path: readonly string[];
401
+ };
402
+ /**
403
+ * Abstract settings service. Providers implement raw-document storage
404
+ * (`load`/`persist`) and push external changes through {@link Settings.publish};
405
+ * the base class owns namespace registration, resolution, validation, change
406
+ * detection, and the `settings/updated` commit event.
407
+ */
408
+ declare abstract class SettingsProvider extends Service {
409
+ private readonly registrations;
410
+ /** Latest published raw document; empty until the provider's first publish. */
411
+ private document;
412
+ /** Per-namespace write chains; settled tails, so a failure never poisons the queue. */
413
+ private readonly writeQueues;
414
+ /** In-flight watcher invocation segments, drained by the dispose teardown. */
415
+ private readonly pendingTails;
416
+ /** Set at service dispose: refuse new writes while queued ones drain. */
417
+ private stopped;
418
+ /** Opaque read of {@link stopped}: control flow cannot narrow it across awaits. */
419
+ private isStopped;
420
+ constructor(ctx: Context);
421
+ /**
422
+ * Load the provider's document once and publish it before the service
423
+ * becomes injectable, and register the write-drain teardown. Providers with
424
+ * their own init (watchers, connections) delegate here first via
425
+ * `yield* super[Service.init]()`; their disposers then run before the drain.
426
+ */
427
+ [Service.init](): AsyncGenerator<() => Promise<void> | void, void, void>;
428
+ /** Whether {@link update} may persist through this provider. */
429
+ abstract readonly writable: boolean;
430
+ /**
431
+ * Absolute path of the provider's user-editable document, when its storage
432
+ * is one local file. Configuration surfaces use this only as availability
433
+ * metadata; the guarded open operation resolves the path again Host-side.
434
+ * Non-file providers leave it undefined and expose no open-document affordance.
435
+ * @returns the absolute local document path, or undefined for non-file storage.
436
+ */
437
+ get documentPath(): string | undefined;
438
+ /**
439
+ * Prepare the provider's user-editable document for a native editor. File
440
+ * providers may materialize an absent document before returning its path;
441
+ * non-file providers return undefined.
442
+ * @returns the absolute local document path, or undefined for non-file storage.
443
+ */
444
+ prepareDocument(): Promise<string | undefined>;
445
+ /**
446
+ * Read the provider's current raw document (namespace to raw section).
447
+ * @returns the detached raw document.
448
+ */
449
+ protected abstract load(): Promise<Record<string, unknown>>;
450
+ /**
451
+ * Durably store one namespace's merged user section.
452
+ * @param ns - the namespace being written.
453
+ * @param section - the complete merged user section to store.
454
+ */
455
+ protected abstract persist(ns: SettingsNamespace, section: Record<string, unknown>): Promise<void>;
456
+ /**
457
+ * Register a namespace schema and receive its owner scope. The registration
458
+ * is an effect on the calling plugin's fiber: disposing that fiber removes
459
+ * the namespace and its observers. An invalid stored section fails the
460
+ * registration itself — the earliest point where the schema can judge it.
461
+ * @param ns - unique namespace; duplicate registration fails loud.
462
+ * @param schema - schemastery schema resolving this namespace's value.
463
+ * @param options - composition `base` layer and effect timing.
464
+ * @returns the owner scope for reads, observation, and updates.
465
+ */
466
+ register<T>(ns: SettingsNamespace, schema: Schema<T>, options?: SettingsRegisterOptions<T>): SettingsScope<T>;
467
+ /**
468
+ * Describe every registered namespace for configuration surfaces, including
469
+ * the composition `base` and raw user layers so a form can mark which fields
470
+ * the user overrode (presence in `user`) and what a reset returns to.
471
+ * @param options - redaction switch; wire surfaces must redact.
472
+ * @returns one descriptor per registered namespace, in registration order.
473
+ */
474
+ describe(options?: SettingsDescribeOptions): SettingsDescriptor[];
475
+ /**
476
+ * Read one registered namespace's resolved value.
477
+ * @param ns - the namespace to read.
478
+ * @returns the resolved value, or `undefined` while unregistered.
479
+ */
480
+ get(ns: SettingsNamespace): unknown;
481
+ /**
482
+ * Merge a patch into one registered namespace's user layer, validate the
483
+ * resolved candidate, persist through the provider, then commit and emit.
484
+ * A validation failure rejects before anything is persisted. Writes to one
485
+ * namespace are serialized: concurrent updates apply in call order, each
486
+ * merging over the previous write's committed section.
487
+ * @param ns - the registered namespace to update.
488
+ * @param patch - plain-object patch over the user section.
489
+ * @param expectedRevision - the descriptor `revision` the caller read; a
490
+ * namespace that moved past it rejects with {@link SettingsConflictError}.
491
+ */
492
+ update(ns: SettingsNamespace, patch: object, expectedRevision?: number): Promise<void>;
493
+ /**
494
+ * Replace one registered namespace's user section wholesale, validate,
495
+ * persist, then commit and emit. Keys absent from `section` fall back to the
496
+ * composition `base` and schema defaults — this is the removal/reset path a
497
+ * merge-only patch cannot express (`replace({})` re-inherits everything).
498
+ * @param ns - the registered namespace to replace.
499
+ * @param section - the complete next user section.
500
+ * @param expectedRevision - the descriptor `revision` the caller read; a
501
+ * namespace that moved past it rejects with {@link SettingsConflictError}.
502
+ */
503
+ replace(ns: SettingsNamespace, section: object, expectedRevision?: number): Promise<void>;
504
+ /**
505
+ * Apply path-addressed edits to one registered namespace's user section,
506
+ * validate, persist, then commit and emit. The ops are applied to the
507
+ * section as it stands when the write reaches the front of the queue, so a
508
+ * caller never has to restate fields it did not touch — and, crucially,
509
+ * cannot delete fields it never saw. This is the write path for any caller
510
+ * holding a redacted view; `replace` remains the wholesale reset.
511
+ * @param ns - the registered namespace to edit.
512
+ * @param ops - ordered path edits; later ops observe earlier ones.
513
+ * @param expectedRevision - the descriptor `revision` the caller read; a
514
+ * namespace that moved past it rejects with {@link SettingsConflictError}.
515
+ */
516
+ mutate(ns: SettingsNamespace, ops: readonly SettingsPathOp[], expectedRevision?: number): Promise<void>;
517
+ /** Validate a write, then queue it on the namespace's serialized write chain. */
518
+ private write;
519
+ /**
520
+ * Provider hook: commit a complete raw document observed in storage. Each
521
+ * registered namespace re-resolves; an invalid section keeps that
522
+ * namespace's last good value and warns, other namespaces still commit.
523
+ * @param doc - the detached raw document (unregistered sections preserved).
524
+ * @param source - change origin; defaults to `provider`.
525
+ */
526
+ protected publish(doc: Record<string, unknown>, source?: SettingsUpdateSource): void;
527
+ /** Read one namespace's raw user section, rejecting non-object sections. */
528
+ private section;
529
+ /** Resolve one namespace value: schema defaults, then `base`, then the user layer. */
530
+ private resolve;
531
+ /**
532
+ * Advance a namespace's revision when its RAW section changed, and announce
533
+ * it. Deliberately independent of {@link commit}'s resolved-value equality:
534
+ * storing an override equal to the composition base leaves the resolved
535
+ * value alone but changes what the document says, which is exactly what a
536
+ * configuration surface must re-read.
537
+ */
538
+ private bumpRevision;
539
+ /** Contained fan-out of `settings/document-updated`, mirroring {@link commit}'s. */
540
+ private emitDocumentUpdated;
541
+ /** Commit a resolved value when changed: swap, notify watchers, emit the event. */
542
+ private commit;
543
+ /** Contained-watcher diagnostic shared by the sync and async failure paths. */
544
+ private warnWatcherFailure;
545
+ /** Contained-listener diagnostic shared by the sync and async failure paths. */
546
+ private warnListenerFailure;
547
+ }
548
+ //#endregion
549
+ //#region ../../node_modules/@deepseek-ai/dsh-attachment/lib/types/brand.d.ts
550
+ /** Opaque content-addressed identifier for one immutable attachment object. */
551
+ type AttachmentId = Branded<'AttachmentId'>;
552
+ /**
553
+ * Brand a validated storage identifier.
554
+ * @param value - backend-produced opaque identifier.
555
+ * @returns the branded identifier.
556
+ */
557
+ declare function AttachmentId(value: string): AttachmentId;
558
+ /** Opaque deterministic identity for one request-image transformation. */
559
+ type ImageVariantId = Branded<'ImageVariantId'>;
560
+ /**
561
+ * Brand a validated request-image transformation identifier.
562
+ * @param value - attachment-provider-produced opaque identifier.
563
+ * @returns the branded identifier.
564
+ */
565
+ declare function ImageVariantId(value: string): ImageVariantId;
566
+ //#endregion
567
+ //#region ../../node_modules/@deepseek-ai/dsh-attachment/lib/types/types.d.ts
568
+ /** Raster image formats accepted by the version-one attachment path. */
569
+ type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif';
570
+ /** Durable, serializable reference to one immutable normalized image. */
571
+ interface ImageAttachmentRef {
572
+ /** Opaque storage identifier; never a filesystem path or bearer URL. */
573
+ attachmentId: AttachmentId;
574
+ /** Media type verified from the stored bytes. */
575
+ mediaType: ImageMediaType;
576
+ /** Exact encoded byte length. */
577
+ bytes: number;
578
+ /** Intrinsic encoded width in pixels. */
579
+ width: number;
580
+ /** Intrinsic encoded height in pixels. */
581
+ height: number;
582
+ /** Optional display name stripped of local path information. */
583
+ name?: string;
584
+ /**
585
+ * Input dimensions after applying EXIF orientation and before normalization
586
+ * scaling. Present only when normalization reduced the image.
587
+ */
588
+ originalDimensions?: {
589
+ width: number;
590
+ height: number;
591
+ };
592
+ }
593
+ /** Deployment-resolved limits used by upload admission and request buffering. */
594
+ interface ImageAttachmentLimits {
595
+ maxImageBytes: number;
596
+ maxImagesPerMessage: number;
597
+ maxMessageImageBytes: number;
598
+ maxImagePixels: number;
599
+ /** Maximum intrinsic width and maximum intrinsic height in pixels for one image. */
600
+ maxImageDimension: number;
601
+ mediaTypes: readonly ImageMediaType[];
602
+ }
603
+ /** Request to validate and durably commit one image. */
604
+ interface SaveImageAttachment {
605
+ data: Uint8Array;
606
+ /** Caller-declared media type, checked against fully decoded bytes. */
607
+ mediaType: ImageMediaType;
608
+ /** Optional browser/provider display name; it is never interpreted as a path. */
609
+ name?: string;
610
+ }
611
+ /** Stored image bytes returned after reference and digest verification. */
612
+ interface StoredImageAttachment {
613
+ ref: ImageAttachmentRef;
614
+ data: Uint8Array;
615
+ }
616
+ /** Deterministic request-image policy selected by one exact model route. */
617
+ interface ImageRequestPolicy {
618
+ /** Maximum width multiplied by height after aspect-preserving projection. */
619
+ maxPixels: number;
620
+ /** Encoded-byte cap before base64 expansion or Files API upload. */
621
+ maxBytes: number;
622
+ }
623
+ /** Cached request version derived from one provider-independent normalized attachment. */
624
+ interface RequestImageAttachment {
625
+ /** Cache and upload-index key over the attachment id, policy, and fixed encoder parameters. */
626
+ variantId: ImageVariantId;
627
+ /** Durable normalized attachment from which this request version was derived. */
628
+ attachment: ImageAttachmentRef;
629
+ /** Encoded request bytes. */
630
+ data: Uint8Array;
631
+ mediaType: ImageMediaType;
632
+ bytes: number;
633
+ width: number;
634
+ height: number;
635
+ /** Provider-compatible sample depth proven after request encoding. */
636
+ depth: 'uchar';
637
+ /** Provider-compatible color space proven after request encoding. */
638
+ space: 'srgb';
639
+ /** Whether the encoded request version retains an alpha channel. */
640
+ hasAlpha: boolean;
641
+ }
642
+ //#endregion
643
+ //#region ../../node_modules/@deepseek-ai/dsh-attachment/lib/types/index.d.ts
644
+ declare module '@deepseek-ai/cordis' {
645
+ interface Context {
646
+ attachments: AttachmentStore;
647
+ }
648
+ }
649
+ /** Immutable binary attachment service. Implementations validate bytes before publishing a reference. */
650
+ declare abstract class AttachmentStore extends Service {
651
+ constructor(ctx: Context);
652
+ /** Deployment-resolved image policy used by authoritative and fast-path validation. */
653
+ abstract readonly imageLimits: ImageAttachmentLimits;
654
+ /**
655
+ * Validate one image without persisting it.
656
+ * Batch callers validate every member before saving any member.
657
+ * @param input - encoded bytes, declared media type, and optional display name.
658
+ * @returns completion after the encoded raster has been fully decoded.
659
+ */
660
+ abstract validateImage(input: SaveImageAttachment): Promise<void>;
661
+ /**
662
+ * Validate one ordered image batch before committing any member.
663
+ * Validation failures start no writes; storage failures return no partial
664
+ * references, although already published content-addressed objects may stay
665
+ * unreachable until a future retention policy collects them.
666
+ * @param inputs - encoded images in their owning message order.
667
+ * @returns durable references in the exact input order.
668
+ */
669
+ protected validateImageBatch(inputs: readonly SaveImageAttachment[]): void;
670
+ /**
671
+ * Validate and durably commit one ordered image batch.
672
+ * @param inputs - encoded images in owning-message order.
673
+ * @returns durable normalized attachment references in the same order after every member succeeds.
674
+ */
675
+ saveImages(inputs: readonly SaveImageAttachment[]): Promise<readonly ImageAttachmentRef[]>;
676
+ /**
677
+ * Validate and durably commit one image before its owning session event is appended.
678
+ * The returned reference describes the persisted normalized image. When
679
+ * normalization reduces the raster, its `originalDimensions` records the
680
+ * orientation-applied input dimensions.
681
+ * @param input - encoded bytes, declared media type, and optional display name.
682
+ * @returns the durable content-addressed normalized image reference.
683
+ */
684
+ abstract saveImage(input: SaveImageAttachment): Promise<ImageAttachmentRef>;
685
+ /**
686
+ * Read one image and verify that bytes still match the recorded reference.
687
+ * @param ref - durable reference from the session log.
688
+ * @param signal - optional cancellation for backend read and verification work.
689
+ * @returns the verified bytes and normalized attachment reference.
690
+ * @throws the signal reason when aborted, or a storage error when verification fails.
691
+ */
692
+ abstract readImage(ref: ImageAttachmentRef, signal?: AbortSignal): Promise<StoredImageAttachment>;
693
+ /**
694
+ * Generate or read one deterministic model-request version from the stored normalized image.
695
+ * @param ref - durable provider-independent normalized attachment reference.
696
+ * @param policy - exact route pixel and encoded-byte budget.
697
+ * @param signal - optional cancellation.
698
+ * @returns request bytes and the cache/upload identity covering every transform input.
699
+ */
700
+ readImageRequest(ref: ImageAttachmentRef, policy: ImageRequestPolicy, signal?: AbortSignal): Promise<RequestImageAttachment>;
701
+ }
702
+ //#endregion
703
+ //#region ../../node_modules/@deepseek-ai/dsh-llm/lib/types/brand.d.ts
704
+ /** Stable identity carried by one message across inbox, log, and model-request boundaries. */
705
+ type MessageId = Branded<'MessageId'>;
706
+ /**
707
+ * Brand a message identifier.
708
+ * @param id - the opaque message identifier.
709
+ * @returns the same string, branded; no validation is performed.
710
+ */
711
+ declare function MessageId(id: string): MessageId;
712
+ /**
713
+ * Correlates a model-issued tool call with its result. Provider-issued for
714
+ * real adapters; synthesized by mocks/assembler fallbacks.
715
+ */
716
+ type CallId = Branded<'CallId'>;
717
+ /**
718
+ * Brand a string as a {@link CallId}.
719
+ * @param id - the provider-issued (or synthesized) call id.
720
+ * @returns the same string, branded; no validation is performed.
721
+ */
722
+ declare function CallId(id: string): CallId;
723
+ /** Provider-issued request identifier retained for diagnostics across package boundaries. */
724
+ type ProviderRequestId = Branded<'ProviderRequestId'>;
725
+ /**
726
+ * Brand a provider-issued request identifier.
727
+ * @param id - the opaque provider-issued string.
728
+ * @returns the same string, branded; no validation is performed.
729
+ */
730
+ declare function ProviderRequestId(id: string): ProviderRequestId;
731
+ /** Adapter-owned identifier for one model's selectable reasoning effort. */
732
+ type ReasoningEffortId = Branded<'ReasoningEffortId'>;
733
+ /**
734
+ * Brand an adapter-owned reasoning-effort identifier.
735
+ * @param id - the opaque identifier exposed by one model capability.
736
+ * @returns the same string, branded; no validation is performed.
737
+ */
738
+ declare function ReasoningEffortId(id: string): ReasoningEffortId;
739
+ //#endregion
740
+ //#region ../../node_modules/@deepseek-ai/dsh-llm/lib/types/message.d.ts
741
+ /** Provider/model identity and adapter-private replay data for an assistant message. */
742
+ interface AssistantProvenance {
743
+ /** Provider route that produced the message. */
744
+ provider: string;
745
+ /** Provider model id that produced the message. */
746
+ model: string;
747
+ /**
748
+ * Lossless-JSON adapter state needed to replay the provider response.
749
+ * `LlmRuntime` exposes it to a target adapter only when that adapter instance
750
+ * currently owns both this historical provider and the target provider.
751
+ */
752
+ replayState?: unknown;
753
+ }
754
+ /** Required source of an assistant message produced by a routed model. */
755
+ interface ModelMessageSource extends AssistantProvenance {
756
+ kind: 'model';
757
+ }
758
+ /** Required source of a user-role message carrying one tool result. */
759
+ interface ToolMessageSource {
760
+ kind: 'tool';
761
+ callId: CallId;
762
+ }
763
+ /** One named contribution to a `snapshot`-form context, in assembly order. */
764
+ interface ContextSnapshotSection {
765
+ /** The contributing subsystem's name. */
766
+ readonly name: string;
767
+ /** That contribution's model-facing text, exactly as assembled. */
768
+ readonly text: string;
769
+ }
770
+ /**
771
+ * Producer-declared {@link ContextForm} and the fields that form requires,
772
+ * mixed into the source types that carry one.
773
+ *
774
+ * Discriminated by `form` so a producer cannot select a form without the
775
+ * fields needed to present it: a `notice` must record its one-line
776
+ * account, a `snapshot` its sections. Omitting `form` stays valid — an
777
+ * undeclared context is the documented default.
778
+ */
779
+ type ContextFormed = {
780
+ readonly form?: never;
781
+ } | {
782
+ readonly form: 'instructions';
783
+ } | {
784
+ readonly form: 'catalog';
785
+ } | {
786
+ readonly form: 'snapshot';
787
+ /** The named contributions this snapshot assembled, in order. */
788
+ readonly sections: readonly ContextSnapshotSection[];
789
+ } | {
790
+ readonly form: 'notice';
791
+ /** One-line account of what happened, shown without expanding the row. */
792
+ readonly summary: string;
793
+ } | {
794
+ readonly form: 'relay';
795
+ } | {
796
+ readonly form: 'recall';
797
+ };
798
+ /**
799
+ * Where a message (or injected content) came from.
800
+ * Merge-extensible sum type — plugins add their own `kind`s.
801
+ */
802
+ interface MessageSourceMap {
803
+ user: {
804
+ kind: 'user';
805
+ };
806
+ plugin: {
807
+ kind: 'plugin';
808
+ plugin: string;
809
+ } & ContextFormed;
810
+ model: ModelMessageSource;
811
+ tool: ToolMessageSource;
812
+ }
813
+ /** Any known message source, derived from {@link MessageSourceMap}; switch on `kind` and fall through unknowns (merge-extensible). */
814
+ type MessageSource = MessageSourceMap[keyof MessageSourceMap];
815
+ /** One immutable message representation shared by delivery, durable history, and model requests. */
816
+ interface Message {
817
+ /** Stable identity preserved across every representation boundary. */
818
+ readonly id: MessageId;
819
+ /** Provider-neutral conversation role. */
820
+ readonly role: 'system' | 'user' | 'assistant';
821
+ /** Exact model-facing blocks. */
822
+ readonly content: ContentBlock[];
823
+ /** Required source fields supplied by the producer. */
824
+ readonly source: MessageSource;
825
+ }
826
+ /** A user-role specialization of the one shared message representation. */
827
+ interface UserMessage extends Message {
828
+ readonly role: 'user';
829
+ }
830
+ /** A model-produced assistant specialization of the shared message representation. */
831
+ interface AssistantMessage extends Message {
832
+ readonly role: 'assistant';
833
+ readonly source: ModelMessageSource;
834
+ }
835
+ /** A tool-result specialization whose model-facing block retains call correlation. */
836
+ interface ToolResultMessage extends Message {
837
+ readonly role: 'user';
838
+ readonly content: [ToolResultBlock];
839
+ readonly source: ToolMessageSource;
840
+ }
841
+ //#endregion
842
+ //#region ../../node_modules/@deepseek-ai/dsh-llm/lib/types/types.d.ts
843
+ declare module '@deepseek-ai/cordis' {
844
+ interface Events {
845
+ /**
846
+ * The provider topology changed: an adapter registered or unregistered
847
+ * routes, or the configurable-provider directory gained or lost entries.
848
+ * This payload-free registry notification fires at each commit point
849
+ * (including registration disposal); consumers re-read `listProviders()`,
850
+ * `listModels()`, or `listConfigurableProviders()` for the new state.
851
+ * Observer failures are contained and cannot veto the registry mutation.
852
+ * @mode emit
853
+ */
854
+ 'llm/adapters-updated'(): void;
855
+ }
856
+ }
857
+ /** Serializable provider or transport failure facts; policy decides whether they are retryable. */
858
+ interface LlmFailure {
859
+ /** Human-readable provider or transport failure. */
860
+ readonly message: string;
861
+ /** Stable provider-neutral machine-routing code. */
862
+ readonly code: string;
863
+ /** HTTP status returned by the provider, when available. */
864
+ readonly status?: number;
865
+ /** Provider-requested delay in milliseconds, when valid and available. */
866
+ readonly providerRetryAfterMs?: number;
867
+ /** Opaque provider-issued request identifier for diagnostics. */
868
+ readonly requestId?: ProviderRequestId;
869
+ }
870
+ /** Plain text visible to the end user. */
871
+ interface TextBlock {
872
+ type: 'text';
873
+ text: string;
874
+ }
875
+ /** Reasoning / thinking content, distinct from visible text. */
876
+ interface ReasoningBlock {
877
+ type: 'reasoning';
878
+ text: string;
879
+ }
880
+ /**
881
+ * A durable raster image reference, valid in user or assistant content. The
882
+ * block is deliberately role-neutral; assistant-side rendering is forward
883
+ * compatibility — the current production adapters declare text-only output,
884
+ * so only user content carries images today.
885
+ */
886
+ interface ImageBlock {
887
+ type: 'image';
888
+ /** Immutable bytes and intrinsic display metadata owned by the attachment service. */
889
+ attachment: ImageAttachmentRef;
890
+ }
891
+ /** A tool invocation requested by the model. */
892
+ interface ToolCallBlock {
893
+ type: 'tool-call';
894
+ /** Provider-issued call id; correlates with the matching tool result. */
895
+ id: CallId;
896
+ name: string;
897
+ /** Raw JSON string as produced by the model. */
898
+ arguments: string;
899
+ }
900
+ /** The result of a tool invocation, sent back to the model. */
901
+ interface ToolResultBlock {
902
+ type: 'tool-result';
903
+ toolCallId: CallId;
904
+ content: ContentBlock[];
905
+ isError?: boolean;
906
+ }
907
+ /**
908
+ * Merge-extensible content blocks keyed by `type`. New core blocks must land
909
+ * with adapter, UI, and compaction support.
910
+ */
911
+ interface ContentBlockMap {
912
+ 'text': TextBlock;
913
+ 'reasoning': ReasoningBlock;
914
+ 'image': ImageBlock;
915
+ 'tool-call': ToolCallBlock;
916
+ 'tool-result': ToolResultBlock;
917
+ }
918
+ /** The block `type` tag vocabulary; widens as plugins add entries to {@link ContentBlockMap}. */
919
+ type ContentBlockType = keyof ContentBlockMap;
920
+ /** Any known content block, derived from {@link ContentBlockMap}; switch on `type` and fall through unknowns (merge-extensible). */
921
+ type ContentBlock = ContentBlockMap[ContentBlockType];
922
+ /**
923
+ * Why a model response stopped.
924
+ * Merge-extensible so adapters can surface provider-specific reasons.
925
+ */
926
+ interface FinishReasonMap {
927
+ 'stop': {
928
+ kind: 'stop';
929
+ };
930
+ 'tool-calls': {
931
+ kind: 'tool-calls';
932
+ };
933
+ 'max-tokens': {
934
+ kind: 'max-tokens';
935
+ };
936
+ 'aborted': {
937
+ kind: 'aborted';
938
+ failure: LlmFailure;
939
+ };
940
+ 'error': {
941
+ kind: 'error';
942
+ failure: LlmFailure;
943
+ };
944
+ }
945
+ /** Any known finish reason, derived from {@link FinishReasonMap}; switch on `kind` and fall through unknowns (merge-extensible). */
946
+ type FinishReason = FinishReasonMap[keyof FinishReasonMap];
947
+ /**
948
+ * Token accounting for one model call (cache fields are optional).
949
+ *
950
+ * Counts are DISJOINT: `inputTokens` is uncached input only; cached input is
951
+ * reported separately as `cacheReadTokens`/`cacheWriteTokens` (billed input =
952
+ * sum of the three). Adapters whose providers fold cache hits into a total
953
+ * prompt count (DeepSeek's `prompt_tokens`) subtract them out.
954
+ */
955
+ interface TokenUsage {
956
+ inputTokens: number;
957
+ outputTokens: number;
958
+ cacheReadTokens?: number;
959
+ cacheWriteTokens?: number;
960
+ reasoningTokens?: number;
961
+ }
962
+ /** Display metadata for one registered provider route. */
963
+ interface LlmProviderInfo {
964
+ /** Provider route key used by {@link GenerateOptions.provider}. */
965
+ id: string;
966
+ /** Human-readable provider name for selectors and diagnostics. */
967
+ name: string;
968
+ }
969
+ /** Merge-extensible provider model modality vocabulary. */
970
+ interface ModelModalityMap {
971
+ text: 'text';
972
+ image: 'image';
973
+ }
974
+ /** Any declared provider model modality. */
975
+ type ModelModality = ModelModalityMap[keyof ModelModalityMap];
976
+ /**
977
+ * One provider route an adapter plugin can activate through configuration,
978
+ * whether or not the route is currently registered. Configuration surfaces
979
+ * merge this directory with `listProviders()` to offer every configurable
980
+ * provider alongside its live/dormant state.
981
+ */
982
+ interface LlmConfigurableProvider {
983
+ /** Provider route key this entry activates when configured. */
984
+ provider: string;
985
+ /** Human-readable provider name for configuration surfaces. */
986
+ displayName: string;
987
+ /** User-settings namespace whose section configures this provider. */
988
+ settingsNs: string;
989
+ /**
990
+ * Path from that namespace's section root to this provider's profile
991
+ * object; empty when the whole section is the profile.
992
+ */
993
+ settingsPath: readonly string[];
994
+ /**
995
+ * Whether the owning adapter knows this route only because configuration
996
+ * declared it — a gateway or self-hosted server it ships nothing about.
997
+ * Absent means the adapter draws no such distinction; false means it does
998
+ * and this route is one of its own. Only the adapter can answer: a stored
999
+ * profile is how a user-added route AND a corrected shipped one both look
1000
+ * from outside.
1001
+ */
1002
+ declared?: boolean;
1003
+ }
1004
+ /**
1005
+ * One interrogation of a provider endpoint that configuration has not stored
1006
+ * yet. Configuration surfaces send the draft a user is still editing, so the
1007
+ * request carries the endpoint and credential directly instead of naming a
1008
+ * route: a provider being added has no route to name.
1009
+ */
1010
+ interface LlmModelDiscoveryRequest {
1011
+ /**
1012
+ * Route the draft is editing, when it edits an existing one. A route whose
1013
+ * adapter already knows its models answers from that knowledge instead of
1014
+ * asking the endpoint — the adapter's own registry is the better answer, and
1015
+ * it costs no network call.
1016
+ */
1017
+ provider?: string;
1018
+ /**
1019
+ * Endpoint to interrogate. Optional because a route the adapter already
1020
+ * describes needs none; a route it does not must supply one.
1021
+ */
1022
+ baseURL?: string;
1023
+ /** Wire protocol the endpoint speaks, when the draft names one. */
1024
+ api?: string;
1025
+ /** Credential for this interrogation alone; the harness never stores it. */
1026
+ apiKey?: string;
1027
+ /** Caller cancellation; implementations must settle promptly after it aborts. */
1028
+ signal?: AbortSignal;
1029
+ }
1030
+ /**
1031
+ * One model an endpoint reports about itself. Every field but the id is
1032
+ * optional because most provider listings disclose an id and nothing else;
1033
+ * a surface adopting one of these still owes the capacities its adapter needs.
1034
+ */
1035
+ interface LlmDiscoveredModel {
1036
+ /** Model id the endpoint accepts. */
1037
+ id: string;
1038
+ /** Human-readable name when the endpoint supplies one. */
1039
+ name?: string;
1040
+ /** Maximum combined request and response context, when disclosed. */
1041
+ contextWindow?: number;
1042
+ /** Maximum output tokens, when disclosed. */
1043
+ maxTokens?: number;
1044
+ }
1045
+ /** One adapter-discovered model; catalog membership is advisory, not request validation. */
1046
+ interface LlmModelInfo {
1047
+ /** Provider route that owns this model entry. */
1048
+ provider: string;
1049
+ /** Model id passed to {@link GenerateOptions.model}. */
1050
+ id: string;
1051
+ /** Human-readable model name for selectors. */
1052
+ name: string;
1053
+ /** Optional user-facing distinction from otherwise similar models. */
1054
+ description?: string;
1055
+ /** Accepted request modalities; absent means unknown, while an explicit omission is negative capability. */
1056
+ inputModalities?: readonly ModelModality[];
1057
+ }
1058
+ /** Provider-owned context capacity for one exact provider/model route. */
1059
+ interface LlmModelContext {
1060
+ /** Maximum combined request and response context in tokens. */
1061
+ contextWindow: number;
1062
+ }
1063
+ /** Display metadata for one adapter-owned reasoning effort. */
1064
+ interface LlmReasoningEffortInfo {
1065
+ /** Opaque stable value accepted by {@link GenerateOptions.reasoningEffort}. */
1066
+ id: ReasoningEffortId;
1067
+ /** Human-readable effort name for selectors and diagnostics. */
1068
+ name: string;
1069
+ /** Optional user-facing distinction from otherwise similar efforts. */
1070
+ description?: string;
1071
+ }
1072
+ /** Selectable reasoning efforts for one exact provider/model route. */
1073
+ interface LlmModelReasoningInfo {
1074
+ /** Supported efforts in adapter-preferred display order. */
1075
+ efforts: readonly LlmReasoningEffortInfo[];
1076
+ /**
1077
+ * Adapter-configured default materialized into requests when callers omit
1078
+ * an effort. Absence preserves the provider's own default.
1079
+ */
1080
+ defaultEffort?: ReasoningEffortId;
1081
+ }
1082
+ /** Exact-route model metadata resolved by its owning adapter. */
1083
+ interface LlmResolvedModelInfo extends LlmModelInfo {
1084
+ /** Provider-owned context capacity when known. */
1085
+ context?: LlmModelContext;
1086
+ /** Adapter-configured per-request output cap materialized when callers omit one. */
1087
+ defaultMaxTokens?: number;
1088
+ /** Adapter-owned selectable reasoning levels when exposed. */
1089
+ reasoning?: LlmModelReasoningInfo;
1090
+ }
1091
+ /**
1092
+ * Adapter-private lossless-JSON state for replaying a successful response,
1093
+ * carried by a terminal `finish` chunk and stored on the assembled assistant
1094
+ * message's model source. Both halves stay opaque to the harness; only the
1095
+ * split is shared vocabulary, so assembly can keep stored metadata aligned
1096
+ * with stored content without reading either half.
1097
+ */
1098
+ interface ReplayEnvelope {
1099
+ /** Response-level adapter-private metadata (ids, native stop reason). */
1100
+ response: unknown;
1101
+ /**
1102
+ * Per-block adapter-private metadata, one entry per emitted block in
1103
+ * first-seen stream order. When assembly drops a block it drops the entry at
1104
+ * the same position; entries whose length does not match the emitted block
1105
+ * count discard the whole envelope. An adapter whose metadata is independent
1106
+ * of block structure omits this field and the envelope passes through
1107
+ * assembly unchanged.
1108
+ */
1109
+ blocks?: readonly unknown[];
1110
+ }
1111
+ /**
1112
+ * Raw streaming protocol emitted by adapters.
1113
+ * Block indexes correlate interleaved deltas, and `block-end` carries the
1114
+ * assembled block. Adapters emit usage before the terminal finish and nothing
1115
+ * afterward; tool arguments remain raw JSON strings. An adapter implementation
1116
+ * may throw, but `LlmRuntime.stream()` normalizes that failure to a terminal
1117
+ * `error` or `aborted` finish before exposing it to consumers.
1118
+ */
1119
+ type StreamChunk = {
1120
+ type: 'block-start';
1121
+ index: number;
1122
+ blockType: ContentBlockType;
1123
+ } | {
1124
+ type: 'text-delta';
1125
+ index: number;
1126
+ text: string;
1127
+ } | {
1128
+ type: 'reasoning-delta';
1129
+ index: number;
1130
+ text: string;
1131
+ } | {
1132
+ type: 'tool-call-delta';
1133
+ index: number;
1134
+ id: CallId;
1135
+ name?: string;
1136
+ argumentsDelta: string;
1137
+ } | {
1138
+ type: 'block-end';
1139
+ index: number;
1140
+ block: ContentBlock;
1141
+ } | {
1142
+ type: 'usage';
1143
+ usage: TokenUsage;
1144
+ } | {
1145
+ type: 'finish';
1146
+ reason: FinishReason;
1147
+ /** Replay metadata for a successful response; see {@link ReplayEnvelope}. */
1148
+ replayState?: ReplayEnvelope;
1149
+ };
1150
+ /**
1151
+ * JSON-schema description of a tool, as sent to the model.
1152
+ *
1153
+ * Declared here (not in dsh-tools) because it is part of {@link GenerateOptions};
1154
+ * dsh-tools' ToolDefinition and dsh-system-prompt's PromptAssembly both import
1155
+ * it from this package.
1156
+ */
1157
+ interface ToolSchema {
1158
+ name: string;
1159
+ description: string;
1160
+ /** JSON Schema object for the arguments. */
1161
+ parameters: Record<string, unknown>;
1162
+ }
1163
+ /** A single model request, fully assembled. */
1164
+ interface GenerateOptions {
1165
+ /** Registered provider route selecting the adapter instance. */
1166
+ provider: string;
1167
+ model: string;
1168
+ /** Adapter-owned reasoning effort selected for this exact model. */
1169
+ reasoningEffort?: ReasoningEffortId;
1170
+ /**
1171
+ * Ordered conversation messages, exactly as the provider sees them (after
1172
+ * the `system` slot). A loop-built request assembles them as
1173
+ * the derived history (dsh-agent-loop); a hand-built one-shot passes any list.
1174
+ */
1175
+ messages: Message[];
1176
+ /** System prompt text (adapters map to the provider's system slot). */
1177
+ system?: string;
1178
+ /** Tool schemas (adapters map to the provider's `tools` field). */
1179
+ tools?: ToolSchema[];
1180
+ temperature?: number;
1181
+ maxTokens?: number;
1182
+ /**
1183
+ * Stop sequences: generation halts as soon as the model produces any one of
1184
+ * these strings (adapters map to the provider's stop field, e.g. OpenAI
1185
+ * `stop`). The stop string itself is not included in the output.
1186
+ */
1187
+ stop?: string[];
1188
+ signal?: AbortSignal;
1189
+ /**
1190
+ * Session identity stamped by the loop for request routing. Replay uses it
1191
+ * to separate cursors; adapters may map it to model-hidden transport metadata.
1192
+ */
1193
+ sessionId?: Branded<'SessionId'>;
1194
+ /**
1195
+ * Provider-neutral classification for an auxiliary model call. Adapters may
1196
+ * map the purpose to model-hidden transport metadata or purpose-specific
1197
+ * generation policy. Ordinary conversation requests leave it unset.
1198
+ */
1199
+ purpose?: 'compaction' | 'session-title';
1200
+ }
1201
+ //#endregion
1202
+ //#region ../../node_modules/@deepseek-ai/dsh-llm/lib/types/retry-policy.d.ts
1203
+ /** Fully resolved backoff shared by both retry modes. */
1204
+ interface ResolvedRetryBackoff {
1205
+ readonly initialDelayMs: number;
1206
+ readonly maxDelayMs: number;
1207
+ readonly jitterRatio: number;
1208
+ }
1209
+ /** Fully resolved bounded transient retry policy. */
1210
+ interface ResolvedNormalRetryPolicy extends ResolvedRetryBackoff {
1211
+ readonly mode: 'normal';
1212
+ readonly maxRetries: number;
1213
+ readonly retryableCodes: readonly string[];
1214
+ }
1215
+ /** Fully resolved unbounded retry policy. */
1216
+ interface ResolvedAlwaysRetryPolicy extends ResolvedRetryBackoff {
1217
+ readonly mode: 'always';
1218
+ }
1219
+ /** Immutable provider policy captured when its adapter route is registered. */
1220
+ type ResolvedRetryPolicy = ResolvedNormalRetryPolicy | ResolvedAlwaysRetryPolicy;
1221
+ //#endregion
1222
+ //#region ../../node_modules/@deepseek-ai/dsh-llm/lib/types/call-config.d.ts
1223
+ /**
1224
+ * Provider, model, reasoning effort, and sampling scalars of one conversation's
1225
+ * requests. Every field maps 1:1 onto the same-named `GenerateOptions` field;
1226
+ * the loop builds requests from the logged header rather than accepting these
1227
+ * per call.
1228
+ */
1229
+ interface LlmCallConfig {
1230
+ provider: string;
1231
+ model: string;
1232
+ reasoningEffort?: ReasoningEffortId;
1233
+ temperature?: number;
1234
+ maxTokens?: number;
1235
+ stop?: string[];
1236
+ }
1237
+ /**
1238
+ * Effective config fields supplied by exact-model adapter resolution rather
1239
+ * than by the caller's request proposal.
1240
+ */
1241
+ interface LlmCallConfigAdapterDefaults {
1242
+ reasoningEffort?: true;
1243
+ maxTokens?: true;
1244
+ }
1245
+ //#endregion
1246
+ //#region ../../node_modules/@deepseek-ai/dsh-llm/lib/types/index.d.ts
1247
+ declare module '@deepseek-ai/cordis' {
1248
+ interface Context {
1249
+ llm: LlmRuntime;
1250
+ }
1251
+ interface Events {
1252
+ /**
1253
+ * Waterfall around every streaming model call (retry, replay, routing).
1254
+ * Bound to the {@link LlmRuntime}; call `next()` to reach the resolved
1255
+ * adapter's stream, or yield your own chunks to short-circuit.
1256
+ * @param options - the full request. A LOOP-built request carries the
1257
+ * process-local {@link markAgentLoopRequest} identity and arrives deep-frozen
1258
+ * (mutation throws): its content is a pure function of the session log (the
1259
+ * reconstructability Agent Note), so listeners read it, never rewrite it.
1260
+ * Hand-built calls do not carry that marker; their messages already obey
1261
+ * the immutable creation contract.
1262
+ * @mode waterfall
1263
+ */
1264
+ 'llm/stream'(this: LlmRuntime, options: GenerateOptions, next: () => AsyncIterable<StreamChunk>): AsyncIterable<StreamChunk>;
1265
+ }
1266
+ }
1267
+ /** One model call whose config and adapter registration were resolved together. */
1268
+ interface PreparedLlmCall {
1269
+ /** Detached, deep-frozen config with any adapter-owned default materialized. */
1270
+ readonly config: LlmCallConfig;
1271
+ /** Immutable retry policy captured with the adapter registration. */
1272
+ readonly retryPolicy: ResolvedRetryPolicy;
1273
+ /** Detached context metadata resolved with the registration-bound call. */
1274
+ readonly context?: LlmModelContext;
1275
+ /** Exact model modalities captured with the adapter dispatch generation. */
1276
+ readonly inputModalities?: readonly ModelModality[];
1277
+ /** Config fields materialized by the captured adapter rather than proposed by the caller. */
1278
+ readonly adapterDefaults: LlmCallConfigAdapterDefaults;
1279
+ /**
1280
+ * Dispatch this call once through the registration captured during
1281
+ * preparation. The request's call-config fields must match {@link config};
1282
+ * reuse or mismatch fails with `INVALID_PREPARED_CALL`.
1283
+ * @param options - fully assembled request carrying the prepared config.
1284
+ * @returns the chunk stream, including the `llm/stream` waterfall.
1285
+ */
1286
+ stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
1287
+ }
1288
+ /** One adapter-owned model-resolution generation bound to its eventual stream call. */
1289
+ interface PreparedAdapterCall {
1290
+ /** Exact model metadata from the same adapter generation as {@link stream}. */
1291
+ readonly model: LlmResolvedModelInfo;
1292
+ /** Dispatch through that generation without re-reading dynamic connection facts. */
1293
+ stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
1294
+ }
1295
+ /**
1296
+ * Provider-wire adapter for the harness message and stream vocabulary. Register implementations
1297
+ * with `ctx.llm.registerAdapter(providers, adapter)`. Every provider HTTP request must include
1298
+ * `attributionHeaders()`; prove the headers are added in the wire request or library header hook. The direct-fetch
1299
+ * DeepSeek and library-backed pi-ai adapters meet this contract through different internals.
1300
+ */
1301
+ declare abstract class LlmAdapter {
1302
+ /**
1303
+ * Describe one provider route owned by this adapter.
1304
+ * @param provider - a route passed to `registerAdapter()` for this instance.
1305
+ * @returns detached display metadata whose id must equal `provider`.
1306
+ */
1307
+ providerInfo(provider: string): LlmProviderInfo;
1308
+ /**
1309
+ * Return the provider-owned retry policy captured with this route.
1310
+ * @param _provider - a route passed to `registerAdapter()` for this instance.
1311
+ * @returns a resolved policy, or `undefined` to use the normal defaults.
1312
+ */
1313
+ providerRetryPolicy(_provider: string): ResolvedRetryPolicy | undefined;
1314
+ /**
1315
+ * List models this adapter can currently advertise for one owned provider.
1316
+ * The result is advisory: an adapter may accept unlisted model ids, and
1317
+ * consumers must not turn absence into request rejection.
1318
+ * @param _provider - one provider route owned by this adapter.
1319
+ * @returns discoverable models in adapter-preferred order.
1320
+ */
1321
+ listModels(_provider: string): Promise<readonly LlmModelInfo[]>;
1322
+ /**
1323
+ * Resolve all metadata available for one exact model. This query is
1324
+ * independent of the advisory catalog and does not validate request routing.
1325
+ * @param provider - one provider route owned by this adapter.
1326
+ * @param model - exact model id passed to {@link GenerateOptions.model}.
1327
+ * @param _signal - cancellation for this exact-model lookup; asynchronous
1328
+ * implementations must settle promptly after it aborts.
1329
+ * @returns provider/model identity plus any context, call-default, and reasoning metadata.
1330
+ */
1331
+ resolveModel(provider: string, model: string, _signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
1332
+ /**
1333
+ * Bind exact model metadata and the eventual request dispatch to one adapter generation.
1334
+ * Dynamic adapters override this so settings changes between preparation and
1335
+ * dispatch cannot combine one generation's capabilities with another's endpoint.
1336
+ * @param provider - registered provider route.
1337
+ * @param model - exact model id.
1338
+ * @param signal - cancellation for model resolution.
1339
+ * @returns model metadata and a one-generation stream entry point.
1340
+ */
1341
+ prepareCall(provider: string, model: string, signal?: AbortSignal): Promise<PreparedAdapterCall>;
1342
+ /**
1343
+ * Stream one model call as raw chunks. The only required method.
1344
+ * @param options - the fully-assembled request; implementations must honor `options.signal`.
1345
+ * @returns the chunk stream, obeying the adapter contract documented on `StreamChunk`.
1346
+ */
1347
+ abstract stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
1348
+ }
1349
+ /**
1350
+ * What {@link LlmRuntime.registerAdapter} returns: the disposer, plus an
1351
+ * atomic route replacement for the same adapter instance.
1352
+ */
1353
+ interface AdapterRegistrationHandle {
1354
+ /** Release every route this registration currently holds. */
1355
+ (): void;
1356
+ /**
1357
+ * Replace this registration's routes with `providers`, keeping the same
1358
+ * adapter instance. The candidate set is validated in full first — a
1359
+ * conflict with another adapter, an invalid name, or bad provider metadata
1360
+ * throws and leaves the current routes untouched — and the swap itself is
1361
+ * one synchronous section, so no request can observe a gap. An empty array
1362
+ * is legal here (a settings section that emptied holds zero routes while
1363
+ * staying registered), unlike an empty initial registration.
1364
+ *
1365
+ * Throws `LlmError` with code `REGISTRATION_DISPOSED` once the registration
1366
+ * has been released: its routes are gone and its disposer has already run,
1367
+ * so anything registered afterwards would have no owner left to release it.
1368
+ * @param providers - the complete next route set for this registration.
1369
+ */
1370
+ replace(providers: string[]): void;
1371
+ }
1372
+ /**
1373
+ * A live configurable-provider registration, disposable and atomically
1374
+ * replaceable — the directory counterpart of {@link AdapterRegistrationHandle}.
1375
+ */
1376
+ interface DirectoryRegistrationHandle {
1377
+ /** Withdraw every entry this registration currently holds. */
1378
+ (): void;
1379
+ /**
1380
+ * Replace this registration's entries with `entries`. The candidate set is
1381
+ * validated in full first — an entry another registration already declares,
1382
+ * a duplicate within the set, or invalid metadata throws and leaves the
1383
+ * current entries untouched — and the swap is one synchronous section, so no
1384
+ * reader observes a gap. An empty array is legal here, unlike an empty
1385
+ * initial registration.
1386
+ *
1387
+ * Throws `LlmError` with code `REGISTRATION_DISPOSED` once the registration
1388
+ * has been disposed.
1389
+ */
1390
+ replace(entries: readonly LlmConfigurableProvider[]): void;
1391
+ }
1392
+ /**
1393
+ * The abstract `llm` service: an adapter registry plus a streaming model-call
1394
+ * API, interceptable via the `llm/stream` waterfall.
1395
+ */
1396
+ declare class LlmRuntime extends Service {
1397
+ private adapters;
1398
+ private directory;
1399
+ private discoveries;
1400
+ constructor(ctx: Context);
1401
+ /** Notify topology observers without letting one broken listener veto the commit. */
1402
+ private emitAdaptersUpdated;
1403
+ /** Contained-listener diagnostic shared by the sync and async failure paths. */
1404
+ private warnAdaptersListenerFailure;
1405
+ /**
1406
+ * Register an adapter for the given provider routes. Throws `LlmError` with code
1407
+ * `DUPLICATE_ADAPTER` if any provider already has an adapter (all-or-nothing).
1408
+ * Disposed with the fiber.
1409
+ * @param providers - every provider route this adapter should serve.
1410
+ * @param adapter - the adapter that streams calls for those providers.
1411
+ * @returns the disposer, carrying {@link AdapterRegistrationHandle.replace}.
1412
+ */
1413
+ registerAdapter(providers: string[], adapter: LlmAdapter): AdapterRegistrationHandle;
1414
+ /**
1415
+ * Validate one candidate route set for `adapter`, treating routes this
1416
+ * registration already holds as available. Nothing is mutated: a rejected
1417
+ * candidate leaves the registry exactly as it was.
1418
+ */
1419
+ private prepareRoutes;
1420
+ /**
1421
+ * Swap this registration's routes for the prepared ones in one synchronous
1422
+ * section, so no observer can see the registry between the release and the
1423
+ * re-registration. The route set's one mutation point is also where
1424
+ * `llm/adapters-updated` is published, so a `replace` announces itself
1425
+ * exactly like a first registration.
1426
+ */
1427
+ private commitRoutes;
1428
+ /**
1429
+ * Describe provider routes with a registered adapter.
1430
+ * @returns detached provider metadata in registration order.
1431
+ */
1432
+ listProviders(): LlmProviderInfo[];
1433
+ /**
1434
+ * Declare provider routes an adapter plugin can activate through
1435
+ * configuration. Registration is all-or-nothing: an empty list, invalid
1436
+ * entry, or a provider already declared by any registration throws
1437
+ * `LlmError` without registering the rest. Disposed with the fiber.
1438
+ * @param entries - every configurable provider this plugin owns.
1439
+ * @returns a handle that withdraws all of them, and can atomically replace them.
1440
+ */
1441
+ registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): DirectoryRegistrationHandle;
1442
+ /**
1443
+ * List every declared configurable provider, registered or dormant.
1444
+ * @returns detached directory entries in declaration order.
1445
+ */
1446
+ listConfigurableProviders(): LlmConfigurableProvider[];
1447
+ /**
1448
+ * Offer to interrogate provider endpoints on behalf of the settings
1449
+ * namespace this plugin owns. The namespace is the key because that is what
1450
+ * a configuration surface already holds from the configurable-provider
1451
+ * directory, and because a provider being *added* has no route to name yet.
1452
+ * Disposed with the fiber.
1453
+ * @param settingsNs - the namespace whose profiles this discovery serves.
1454
+ * @param discover - interrogates one endpoint; must honor `request.signal`.
1455
+ * @returns the disposer that withdraws the offer.
1456
+ */
1457
+ registerModelDiscovery(settingsNs: string, discover: (request: LlmModelDiscoveryRequest) => Promise<readonly LlmDiscoveredModel[]>): () => void;
1458
+ /**
1459
+ * Interrogate one provider endpoint for the models it advertises. The
1460
+ * request describes a draft, not a stored route, so nothing here reads or
1461
+ * writes settings or credentials — the caller owns both, and the reply is
1462
+ * candidate metadata a surface may offer for adoption.
1463
+ * @param settingsNs - namespace whose registered discovery serves this draft.
1464
+ * @param request - the endpoint, protocol, and one-shot credential to use.
1465
+ * @returns the advertised models, deduplicated in endpoint order.
1466
+ */
1467
+ discoverModels(settingsNs: string, request: LlmModelDiscoveryRequest): Promise<LlmDiscoveredModel[]>;
1468
+ /**
1469
+ * Resolve the retry policy captured when one provider route was registered.
1470
+ * @param provider - registered provider route to inspect.
1471
+ * @returns the provider-owned policy, with normal defaults already resolved.
1472
+ */
1473
+ providerRetryPolicy(provider: string): ResolvedRetryPolicy;
1474
+ /** Detach typed adapter-owned modality metadata. */
1475
+ private detachedModalities;
1476
+ /**
1477
+ * Discover models advertised by one registered provider. Catalog membership
1478
+ * is advisory and never changes routing or request validation.
1479
+ * @param provider - registered provider route to inspect.
1480
+ * @returns detached model metadata in adapter-preferred order.
1481
+ */
1482
+ listModels(provider: string): Promise<LlmModelInfo[]>;
1483
+ /**
1484
+ * Resolve and validate all metadata from the adapter that owns one exact
1485
+ * route. The result is detached from adapter-owned objects; catalog
1486
+ * membership remains advisory and does not control request routing.
1487
+ * @param provider - registered provider route to inspect.
1488
+ * @param model - exact model id passed to the adapter.
1489
+ * @param signal - optional cancellation for adapter-owned asynchronous lookup.
1490
+ * @returns exact model identity plus available context and reasoning metadata.
1491
+ */
1492
+ resolveModelInfo(provider: string, model: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
1493
+ private resolveModelInfoFor;
1494
+ /** Validate and detach one adapter-returned exact model result. */
1495
+ private normalizeModelInfo;
1496
+ /**
1497
+ * Validate a conversation call config against its exact model capability and
1498
+ * materialize adapter-configured defaults. Unsupported explicit efforts
1499
+ * reject before provider I/O; no clamping or aliasing is performed. This
1500
+ * standalone query does not bind a later dispatch; use {@link prepareCall}
1501
+ * when logging and streaming must share one adapter registration.
1502
+ * @param config - provider/model route and optional request controls.
1503
+ * @param signal - optional cancellation for adapter-owned capability lookup.
1504
+ * @returns a detached config only when a default must be materialized.
1505
+ */
1506
+ resolveCallConfig(config: LlmCallConfig, signal?: AbortSignal): Promise<LlmCallConfig>;
1507
+ private resolveCallFor;
1508
+ /** Validate request controls against one already-bound exact model result. */
1509
+ private resolveCallWithInfo;
1510
+ /**
1511
+ * Resolve one call under its current adapter registration. The returned
1512
+ * one-shot handle keeps that registration across header logging and dispatch,
1513
+ * so HMR cannot combine one adapter's capability result with another adapter.
1514
+ * @param config - provider/model route and optional request controls.
1515
+ * @param signal - optional cancellation for adapter-owned capability lookup.
1516
+ * @returns a prepared config and its registration-bound stream entry point.
1517
+ */
1518
+ prepareCall(config: LlmCallConfig, signal?: AbortSignal): Promise<PreparedLlmCall>;
1519
+ private registration;
1520
+ /** Remove replay state whose historical route is owned by another adapter. */
1521
+ private forAdapter;
1522
+ /**
1523
+ * Final adapter boundary. Adapter selection, dispatch, iterator construction,
1524
+ * and iteration failures become one terminal failure chunk. Middleware and
1525
+ * downstream consumer failures remain thrown plugin or consumer errors.
1526
+ */
1527
+ private adapterStream;
1528
+ /**
1529
+ * Stream one model call as raw chunks (token-level deltas). Replay state is
1530
+ * retained only when the same adapter instance owns its historical provider
1531
+ * and the target provider. Final adapter selection remains fixed through
1532
+ * asynchronous exact-model resolution and dispatch. Adapter selection,
1533
+ * dispatch, and iteration failures become terminal `error` or `aborted`
1534
+ * finish chunks; middleware, nested-call, cleanup, and consumer failures
1535
+ * remain thrown.
1536
+ * @param options - the full request; `options.provider` selects the adapter.
1537
+ * @returns the chunk stream, possibly wrapped by `llm/stream` listeners.
1538
+ */
1539
+ stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
1540
+ private streamWithRegistration;
1541
+ }
1542
+ //#endregion
1543
+ //#region ../../node_modules/@deepseek-ai/dsh-scope/lib/types/index.d.ts
1544
+ declare const ScopedBrand: unique symbol;
1545
+ /**
1546
+ * A routing-only event receiver built by {@link scopeTarget}. The type
1547
+ * parameter records the subject type for dispatch checking; the carrier does
1548
+ * not expose the subject's properties. Event payloads carry the real subject.
1549
+ */
1550
+ type Scoped<T extends object> = object & {
1551
+ readonly [ScopedBrand]: T;
1552
+ };
1553
+ //#endregion
1554
+ //#region ../../node_modules/@deepseek-ai/dsh-session/lib/types/json.d.ts
1555
+ /** Lossless-JSON validation and detached snapshots for durable session data. @module @deepseek-ai/dsh-session/json */
1556
+ /**
1557
+ * A value that round-trips losslessly through JSON: `null`, a boolean, a finite
1558
+ * number other than negative zero, a string, an array of such values, or a
1559
+ * plain object whose values are such values. Arrays may carry only their dense
1560
+ * indexed elements; extra own properties would be discarded by JSON. TypeScript
1561
+ * cannot distinguish `-0` from `number`, so {@link isJsonValue} and
1562
+ * {@link snapshotJsonValue} enforce these details at runtime. Use this type for
1563
+ * a payload that must survive session-log persistence and replay byte-identically
1564
+ * — e.g. a tool's private presentation `meta`.
1565
+ */
1566
+ type JsonValue = null | boolean | number | string | JsonValue[] | {
1567
+ [key: string]: JsonValue;
1568
+ };
1569
+ //#endregion
1570
+ //#region ../../node_modules/@deepseek-ai/dsh-session/lib/types/types.d.ts
1571
+ /** Identifies one session in the store (and its persistence artifacts). */
1572
+ type SessionId = Branded<'SessionId'>;
1573
+ /**
1574
+ * Brand a string as a {@link SessionId}.
1575
+ * @param id - the raw session id string.
1576
+ * @returns the same string, branded (a compile-time cast — no runtime cost).
1577
+ */
1578
+ declare function SessionId(id: string): SessionId;
1579
+ /**
1580
+ * Immutable validated storage metadata, kept outside the conversation event log.
1581
+ */
1582
+ interface SessionHeader {
1583
+ /**
1584
+ * On-disk format version, stamped from {@link SESSION_FORMAT_VERSION} when the
1585
+ * session is created. A persistence backend rejects any other version on load
1586
+ * (no migration — see the constant).
1587
+ */
1588
+ readonly version: number;
1589
+ /** The session's id (mirrors the {@link Session}'s id). */
1590
+ readonly id: SessionId;
1591
+ /** Non-negative safe-integer Unix epoch milliseconds when the session was created. */
1592
+ readonly createdAt: number;
1593
+ /** Absolute working directory the session was created in (if any). */
1594
+ readonly cwd?: string;
1595
+ /** The session this one was forked from (seed lineage), if any. */
1596
+ readonly parentSession?: SessionId;
1597
+ /**
1598
+ * How many leading events were inherited through a seed. Persisting this
1599
+ * boundary lets resume and replay distinguish parent history from child work.
1600
+ */
1601
+ readonly seedLength?: number;
1602
+ /**
1603
+ * Coarse product classification for a session created as a subagent child.
1604
+ * This is presentation metadata, not proof that the child is continuable.
1605
+ */
1606
+ readonly origin?: 'subagent';
1607
+ /**
1608
+ * Delegation depth: absent (zero) for a top-level session, parent depth + 1
1609
+ * for a subagent child. Persisted so a recursion budget survives restart and
1610
+ * resume — a runtime-only depth would reset a resumed child to top-level.
1611
+ */
1612
+ readonly delegationDepth?: number;
1613
+ /**
1614
+ * Id of the agent preset this session's agent was composed from, when the
1615
+ * deployment composes per session. Durable because the preset decides the
1616
+ * session's tools and prompt: a resume that restored a different composition
1617
+ * would replay history the model can no longer act on.
1618
+ */
1619
+ readonly agentPreset?: string;
1620
+ }
1621
+ /**
1622
+ * Options for creating a {@link Session} via the store. `seed` replays/forks
1623
+ * an existing event log; `meta` carries the caller-supplied storage fields the
1624
+ * store folds into a {@link SessionHeader}.
1625
+ */
1626
+ interface CreateSessionOptions {
1627
+ /** Initial replay or fork history supplied at construction. */
1628
+ readonly seed?: readonly SessionEvent[];
1629
+ /**
1630
+ * Storage metadata read once before publication. `seedLength` is explicit
1631
+ * because a resumed seed contains the full stored log, not only its inherited prefix.
1632
+ */
1633
+ readonly meta?: {
1634
+ readonly cwd?: string;
1635
+ readonly parentSession?: SessionId;
1636
+ readonly createdAt?: number;
1637
+ readonly seedLength?: number;
1638
+ readonly origin?: 'subagent';
1639
+ readonly delegationDepth?: number;
1640
+ readonly agentPreset?: string;
1641
+ };
1642
+ }
1643
+ /**
1644
+ * Fresh storage values transferred to {@link SessionStore.prepare} without a
1645
+ * second serialization copy. Callers retain no mutable aliases.
1646
+ */
1647
+ interface RestoredSessionOptions {
1648
+ /** Fresh detached storage events to validate and freeze in place. */
1649
+ readonly seed: SessionEvent[];
1650
+ /** Fresh detached storage metadata to validate and freeze in place. */
1651
+ readonly meta: SessionHeader;
1652
+ /** Select the persistence ownership-transfer path. */
1653
+ readonly seedSource: 'persistence';
1654
+ }
1655
+ /** Inputs accepted while constructing an unpublished Session. */
1656
+ type PrepareSessionOptions = (CreateSessionOptions & {
1657
+ readonly seedSource?: undefined;
1658
+ }) | RestoredSessionOptions;
1659
+ /** Why an active agent driver was cancelled. */
1660
+ type AgentCancelCause = {
1661
+ readonly kind: 'user';
1662
+ } | {
1663
+ readonly kind: 'parent';
1664
+ } | {
1665
+ readonly kind: 'hook';
1666
+ readonly reason: string;
1667
+ } | {
1668
+ readonly kind: 'disposed';
1669
+ };
1670
+ /** Durable cancellation cause, including imports whose original coarse record carried no cause. */
1671
+ type TurnEndCancelCause = AgentCancelCause | {
1672
+ readonly kind: 'legacy';
1673
+ };
1674
+ /**
1675
+ * Why a turn ended. Merge-extensible sum type.
1676
+ */
1677
+ interface TurnEndReasonMap {
1678
+ completed: {
1679
+ kind: 'completed';
1680
+ };
1681
+ /** A cancellation request interrupted the live turn. */
1682
+ aborted: {
1683
+ kind: 'aborted';
1684
+ reason: TurnEndCancelCause;
1685
+ };
1686
+ blocked: {
1687
+ kind: 'blocked';
1688
+ };
1689
+ /**
1690
+ * The turn failed. `error` is always a structured failure: the `LlmError`
1691
+ * facts verbatim, or `{ message: errorChain(error), code: 'UNKNOWN' }`
1692
+ * flattened from any other error.
1693
+ */
1694
+ error: {
1695
+ kind: 'error';
1696
+ error: LlmFailure;
1697
+ };
1698
+ /** At least one step reached its output-token ceiling, even if a plugin continued the turn. */
1699
+ 'max-tokens': {
1700
+ kind: 'max-tokens';
1701
+ };
1702
+ /**
1703
+ * A persistence backend closed a crash-orphaned turn on reload. The loop never
1704
+ * emits this marker, and the events recorded before the crash remain intact.
1705
+ */
1706
+ interrupted: {
1707
+ kind: 'interrupted';
1708
+ };
1709
+ }
1710
+ /** The union over {@link TurnEndReasonMap} — why a turn ended; plugins extend it by merging variants into the map. */
1711
+ type TurnEndReason = TurnEndReasonMap[keyof TurnEndReasonMap];
1712
+ /**
1713
+ * One entry in an agent's todo list — the unit of the `todo/write`
1714
+ * {@link SessionEventMap} event's whole-list snapshot.
1715
+ *
1716
+ * Deliberately minimal: a human-readable `content` line and a three-state
1717
+ * `status`. No id, priority, or `activeForm` — the list is replaced wholesale
1718
+ * on every write (last-write-wins), so entries need no stable identity. The
1719
+ * three statuses describe the complete portable lifecycle needed by model and
1720
+ * UI consumers.
1721
+ */
1722
+ interface TodoItem {
1723
+ /** What this task is — a short imperative line shown in the UI. */
1724
+ content: string;
1725
+ /** Lifecycle state. `in_progress` marks a task being worked now; parallel work may mark several. */
1726
+ status: 'pending' | 'in_progress' | 'completed';
1727
+ }
1728
+ /**
1729
+ * Logged request state outside derived history: call config, system prompt, and
1730
+ * tools. The latest full `request/header` snapshot reconstructs it; canonical
1731
+ * empty optional fields are absent.
1732
+ */
1733
+ interface EpochHeader {
1734
+ /** The conversation's call configuration (provider, model, reasoning effort, and sampling scalars). */
1735
+ config: LlmCallConfig;
1736
+ /** Effective config fields materialized from the exact adapter rather than proposed by a caller. */
1737
+ adapterDefaults?: LlmCallConfigAdapterDefaults;
1738
+ /** Rendered system prompt text; absent for a system-less request. */
1739
+ system?: string;
1740
+ /** Assembled tool schemas; absent for a tool-less request. */
1741
+ tools?: ToolSchema[];
1742
+ }
1743
+ /** Registration-bound metadata for one resolved model route. */
1744
+ interface RequestContext {
1745
+ /** Registered provider route the metadata belongs to. */
1746
+ provider: string;
1747
+ /** Provider-owned model id the metadata belongs to. */
1748
+ model: string;
1749
+ /** Maximum combined request and response context in tokens, when advertised. */
1750
+ contextWindow?: number;
1751
+ }
1752
+ /**
1753
+ * Why a `request/header` snapshot was appended: `'initial'` — the log's first
1754
+ * header (a new conversation); `'resume'` — a loop instance's first request
1755
+ * over a log that already has header events (process restart, fork seed);
1756
+ * `'change'` — a later request used a different header.
1757
+ */
1758
+ type RequestHeaderReason = 'initial' | 'resume' | 'change';
1759
+ /**
1760
+ * The merge-extensible, append-only source of truth for an agent interaction.
1761
+ * Message history is derived from this log. Every event is lossless JSON and
1762
+ * sequence numbers stay contiguous, including raw chunks, so persistence can
1763
+ * store the canonical log verbatim.
1764
+ */
1765
+ interface SessionEventMap {
1766
+ /**
1767
+ * Opens turn `turn` before the loop claims queued input or runs pre-step.
1768
+ * Rejection, empty input, cancellation, or failure may close it with no
1769
+ * step; otherwise the following identified `user/message` event or batch
1770
+ * records the messages entering the step.
1771
+ */
1772
+ 'turn/start': {
1773
+ turn: number;
1774
+ };
1775
+ /**
1776
+ * Closes turn `turn` with the {@link TurnEndReason} that ended it. A turn
1777
+ * with no entered step has no `step/start` or `step/end`. The loop does not await a
1778
+ * flush at turn boundaries: `dsh-session-checkpoint-policy` owns the
1779
+ * per-request durability checkpoint, and consumers that read storage after
1780
+ * `whenIdle()` flush themselves. Success commits the turn; rejection is
1781
+ * reported live and does not prevent later work.
1782
+ */
1783
+ 'turn/end': {
1784
+ turn: number;
1785
+ reason: TurnEndReason;
1786
+ };
1787
+ /** Opens step `step` of turn `turn` — one model call plus the tool executions it requested. */
1788
+ 'step/start': {
1789
+ turn: number;
1790
+ step: number;
1791
+ };
1792
+ /** Closes step `step` of turn `turn`. */
1793
+ 'step/end': {
1794
+ turn: number;
1795
+ step: number;
1796
+ };
1797
+ /**
1798
+ * A user-role message on the model-visible surface: a direct human prompt
1799
+ * (the queued message claimed for this turn), a synthetic `agent.inject()`
1800
+ * context (file-change notices, subdir AGENTS.md, skill content, cron
1801
+ * notifications, …), or an entered goal continuation round. All three
1802
+ * project their `content` verbatim; `source` tells them apart.
1803
+ */
1804
+ 'user/message': UserMessage;
1805
+ /** Raw stream chunk — token-level replay fidelity. */
1806
+ 'assistant/chunk': {
1807
+ turn: number;
1808
+ step: number;
1809
+ chunk: StreamChunk;
1810
+ };
1811
+ /**
1812
+ * Assembled assistant message for one step (derived history uses this).
1813
+ * Carries the step's `usage` when the adapter reported token accounting, so
1814
+ * the model output and its accounting travel together (there is no separate
1815
+ * usage record). `usage` is absent when the adapter reported none. A turn
1816
+ * cancelled mid-stream finalizes its delivered text/reasoning prefix as this
1817
+ * event with `interrupted: true`; undispatched tool calls are absent. The
1818
+ * marker distinguishes that prefix without re-deriving interruption from turn
1819
+ * boundaries. An aborted turn with no such event streamed no visible content.
1820
+ */
1821
+ 'assistant/message': {
1822
+ turn: number;
1823
+ step: number;
1824
+ message: AssistantMessage;
1825
+ usage?: TokenUsage;
1826
+ interrupted?: true;
1827
+ };
1828
+ /**
1829
+ * The model requested one tool invocation: `name` with the raw `arguments`
1830
+ * JSON string exactly as the model produced it (unparsed). `callId` pairs the
1831
+ * call with its `tool/result`.
1832
+ */
1833
+ 'tool/call': {
1834
+ turn: number;
1835
+ step: number;
1836
+ callId: CallId;
1837
+ name: string;
1838
+ arguments: string;
1839
+ };
1840
+ /**
1841
+ * A completed tool call's model-facing result, optional internal failure
1842
+ * identity, and optional tool-private `meta` presentation payload. `meta` is
1843
+ * opaque to the core (the producing tool owns its shape and reads it back in
1844
+ * `presentResult`) but MUST be JSON-serializable: `Session.append`
1845
+ * runtime-validates all event data with `isJsonValue`, so a non-serializable
1846
+ * `meta` is rejected at the source, and the durable log reproduces the
1847
+ * identical card on replay. Absent
1848
+ * unless the tool attaches one (e.g. `dsh-tool-fs` carries its result-time
1849
+ * contextual diff here).
1850
+ */
1851
+ 'tool/result': {
1852
+ turn: number;
1853
+ step: number;
1854
+ message: ToolResultMessage;
1855
+ error?: {
1856
+ name: string;
1857
+ code: string;
1858
+ };
1859
+ meta?: JsonValue;
1860
+ };
1861
+ /** Whole-list snapshot; latest write wins on replay. Log-only UI state; never derived history. */
1862
+ 'todo/write': {
1863
+ todos: TodoItem[];
1864
+ };
1865
+ /**
1866
+ * Full header for the next request, appended inside its step before dispatch.
1867
+ * It is log-only; the latest snapshot reconstructs the request header.
1868
+ */
1869
+ 'request/header': {
1870
+ header: EpochHeader;
1871
+ reason: RequestHeaderReason;
1872
+ };
1873
+ /**
1874
+ * Route metadata for the next request, logged only when the route or capacity
1875
+ * changes. It does not participate in request reconstruction or header equality.
1876
+ */
1877
+ 'request/context': RequestContext;
1878
+ /**
1879
+ * Marks the end of a constructor seed. Events before it have smaller seq
1880
+ * values and came from the seed (resume, fork, or replay); this lifecycle
1881
+ * produced none of them. This log-only event is the durable projection of
1882
+ * {@link Session.firstLiveSeq}. Its payload is empty — position and `time`
1883
+ * carry the meaning.
1884
+ *
1885
+ * Locate the LAST one in stored history. A seed already ending in one is not
1886
+ * re-marked, so reopening an untouched session does not grow its log per
1887
+ * pickup and the event need not be at the current `firstLiveSeq`.
1888
+ *
1889
+ * `Session`'s constructor is the only legitimate writer. The invariant
1890
+ * companion deliberately constrains nothing here, so a plugin appending one
1891
+ * would silently classify every live bracket before it as seed history.
1892
+ *
1893
+ * An owner of a standalone open/close bracket (`compaction/start` …
1894
+ * `compaction/end`) reads it because seed history and live work are otherwise
1895
+ * byte-identical: an unmatched opening marker before this event belongs to
1896
+ * an ended lifecycle, whatever ended it. NOT a liveness signal about other
1897
+ * writers — a concurrently live session holds its own boundary elsewhere,
1898
+ * so tolerating concurrent writers needs a signal beyond the log.
1899
+ */
1900
+ 'session/end-seed': Record<string, never>;
1901
+ }
1902
+ /** The appendable event-type keys of {@link SessionEventMap}, plugin-merged extensions included. */
1903
+ type SessionEventType = keyof SessionEventMap;
1904
+ /**
1905
+ * The subset of {@link SessionEventType} values whose events produce LLM
1906
+ * messages and are eligible to appear on the ordered surface. Only these
1907
+ * event types may carry {@link SurfaceOp} and {@link SessionEvent.sourceEventSeqs}.
1908
+ */
1909
+ type SurfaceEventType = 'user/message' | 'assistant/message' | 'tool/result';
1910
+ /**
1911
+ * How a session event entered the ordered surface. Only valid on
1912
+ * {@link SurfaceEventType} events.
1913
+ *
1914
+ * - `'append'`: added to the tail — normal path for user/assistant/tool
1915
+ * messages.
1916
+ * - `{ op: 'replace', start, end }`: replaces surface nodes from `start`
1917
+ * (inclusive) through `end` (inclusive) with this node. Both must exist as
1918
+ * surface nodes in the current surface. `start === end` replaces a single
1919
+ * node. The node's {@link SessionEvent.sourceEventSeqs} must include every
1920
+ * shadowed surface node. Used by compaction; any surface-replacing producer
1921
+ * may use it.
1922
+ */
1923
+ type SurfaceOp = 'append' | {
1924
+ op: 'replace';
1925
+ start: number;
1926
+ end: number;
1927
+ };
1928
+ /**
1929
+ * Surface placement and cited source-event seqs for {@link Session.append}. Required on
1930
+ * message-producing events and forbidden on log-only events.
1931
+ */
1932
+ interface SurfaceIntent {
1933
+ surfaceOp: SurfaceOp;
1934
+ /**
1935
+ * Complete set of known source-event seqs. `assistant/message` may use a
1936
+ * present empty array for a known empty provider stream; when the field is
1937
+ * absent, the event does not record which earlier events produced the message.
1938
+ * Other surface events require a non-empty set when this field is present.
1939
+ */
1940
+ sourceEventSeqs?: number[];
1941
+ }
1942
+ /**
1943
+ * One immutable entry in the session log.
1944
+ *
1945
+ * A proper discriminated union over `type` (not independent `type`/`data`
1946
+ * unions), so `switch (event.type)` narrows `event.data` without casts.
1947
+ *
1948
+ * The {@link sourceEventSeqs} and {@link surfaceOp} fields are conditional:
1949
+ * they only exist on {@link SurfaceEventType} variants (`user/message`,
1950
+ * `assistant/message`, `tool/result`).
1951
+ * Non-surface events (boundary markers, chunks, usage, errors) never carry
1952
+ * surface metadata — the compiler enforces this at `Session.append()`
1953
+ * call sites.
1954
+ */
1955
+ type SessionEvent<T extends SessionEventType = SessionEventType> = { [K in SessionEventType]: {
1956
+ type: K;
1957
+ /** Monotonic sequence number within the session. */
1958
+ seq: number;
1959
+ /** Unix epoch milliseconds. */
1960
+ time: number;
1961
+ data: SessionEventMap[K];
1962
+ /**
1963
+ * Marks an event a reader may safely skip when it does not recognize
1964
+ * `type`. Absent means required: a reader meeting an unrecognized type
1965
+ * without this marker MUST refuse to reconstruct the session instead of
1966
+ * silently dropping the event, because an unrecognized required event may
1967
+ * change how the rest of the log is interpreted. A writer sets `true` only
1968
+ * on purely informational records whose loss cannot affect reconstruction;
1969
+ * defaulting to required means a forgotten marker over-refuses (an
1970
+ * inconvenience) rather than silently resuming a gutted session.
1971
+ */
1972
+ ignorable?: true;
1973
+ } & (K extends SurfaceEventType ? {
1974
+ /**
1975
+ * Seq numbers of earlier events that this event cites as sources
1976
+ * (e.g. the `assistant/chunk` seqs that built an `assistant/message`,
1977
+ * or the surface nodes shadowed by a compaction replace node). An
1978
+ * `assistant/message` may carry a present empty array for a known empty
1979
+ * provider stream; when the field is absent, the event does not record which
1980
+ * earlier events produced the message.
1981
+ */
1982
+ sourceEventSeqs?: number[];
1983
+ /** How this event entered the surface; absent for non-surface events. */
1984
+ surfaceOp?: SurfaceOp;
1985
+ } : object); }[T];
1986
+ //#endregion
1987
+ //#region ../../node_modules/@deepseek-ai/dsh-typert-protocol/lib/types/types.d.ts
1988
+ declare const LOOKUP_HOST: unique symbol;
1989
+ declare const LOOKUP_WIRE: unique symbol;
1990
+ declare const CONTEXT_WIRE: unique symbol;
1991
+ /** Type-level association between a Host object and its wire identity. */
1992
+ interface TypertLookup<Host, Wire> {
1993
+ readonly [LOOKUP_HOST]: Host;
1994
+ readonly [LOOKUP_WIRE]: Wire;
1995
+ }
1996
+ /** Extract the Host object associated with one lookup declaration. */
1997
+ type TypertLookupHost<Lookup> = Lookup extends TypertLookup<infer Host, infer _Wire> ? Host : never;
1998
+ /** Extract the wire identity associated with one lookup declaration. */
1999
+ type TypertLookupWire<Lookup> = Lookup extends TypertLookup<infer _Host, infer Wire> ? Wire : never;
2000
+ /** Type-level association between a scoped Context kind and its wire identity. */
2001
+ interface TypertContext<Wire> {
2002
+ readonly [CONTEXT_WIRE]: Wire;
2003
+ }
2004
+ /** Extract the wire identity associated with one scoped Context declaration. */
2005
+ type TypertContextWire<ContextType> = ContextType extends TypertContext<infer Wire> ? Wire : never;
2006
+ /** Merge-extensible Host object lookup declarations. */
2007
+ interface TypertLookupMap {}
2008
+ /** Merge-extensible scoped Context declarations. */
2009
+ interface TypertContextMap {}
2010
+ /** Awaitable disposer returned by Cordis-owned Typert registrations. */
2011
+ type TypertDisposer = () => Promise<void>;
2012
+ type StringKeyOf<Value> = Extract<keyof Value, string>;
2013
+ /** Minimal runtime-schema capability carried by strict generated codecs. */
2014
+ interface TypertSchema<Output = unknown> {
2015
+ /**
2016
+ * Parse and validate one boundary value.
2017
+ * @param value - untrusted boundary value.
2018
+ * @returns the validated value.
2019
+ */
2020
+ parse(value: unknown): Output;
2021
+ }
2022
+ /** Codec attached to one invocation parameter or result. */
2023
+ type TypertCodec = {
2024
+ readonly mode: 'strict';
2025
+ readonly typeSymbol: string;
2026
+ readonly schema: TypertSchema;
2027
+ } | {
2028
+ readonly mode: 'src-json';
2029
+ };
2030
+ /** One ordered business parameter in a Remote invocation. */
2031
+ interface InvocationParameterDescriptor {
2032
+ /** Source-level parameter name. */
2033
+ readonly name: string;
2034
+ /** Required key in the wire `args` object. */
2035
+ readonly wire: string;
2036
+ /** Whether the value is JSON or requires a registered Host lookup. */
2037
+ readonly source: 'json' | 'lookup';
2038
+ /** Lookup key when `source` is `lookup`. */
2039
+ readonly lookup?: string;
2040
+ /** Boundary codec for the wire representation. */
2041
+ readonly codec: TypertCodec;
2042
+ /** Missing wire fields decode to `undefined` only for an explicitly declared `T | undefined`. */
2043
+ readonly acceptsUndefined?: true;
2044
+ }
2045
+ /** Source position retained for diagnostics from generated definitions. */
2046
+ interface InvocationSourceLocation {
2047
+ readonly file: string;
2048
+ readonly line: number;
2049
+ readonly column: number;
2050
+ }
2051
+ /** Carrier-independent description of one exported method invocation. */
2052
+ interface InvocationDescriptor {
2053
+ /** Globally stable generated identity. */
2054
+ readonly id: string;
2055
+ /** Cordis service key owning the method. */
2056
+ readonly service: string;
2057
+ /** Wire namespace, defaulting to the service key. */
2058
+ readonly namespace: string;
2059
+ /** Public instance method name. */
2060
+ readonly method: string;
2061
+ /** Service member invoked when the exported method name is an alias. */
2062
+ readonly implementation?: string;
2063
+ /** Receiver selection mode. */
2064
+ readonly invocation: {
2065
+ readonly kind: 'direct';
2066
+ } | {
2067
+ readonly kind: 'context';
2068
+ readonly context: string;
2069
+ readonly wire: string;
2070
+ readonly codec: TypertCodec;
2071
+ };
2072
+ /** Optional consuming-Context projection for one direct lookup parameter. */
2073
+ readonly scope?: {
2074
+ /** Context kind whose Client binder supplies the identity. */
2075
+ readonly context: string;
2076
+ /** Lookup parameter wire field replaced by the Context identity. */
2077
+ readonly wire: string;
2078
+ };
2079
+ /** Ordered business parameters. */
2080
+ readonly parameters: readonly InvocationParameterDescriptor[];
2081
+ /** Transport cancellation injected after business parameters instead of entering wire args. */
2082
+ readonly cancellation?: {
2083
+ /** Reserved final Host method parameter. */
2084
+ readonly parameter: 'signal';
2085
+ };
2086
+ /** Codec for the resolved method result. */
2087
+ readonly result: TypertCodec;
2088
+ /** Source declaration used only for diagnostics. */
2089
+ readonly sourceLocation?: InvocationSourceLocation;
2090
+ }
2091
+ /** Generated Host contract selected explicitly by a Client assembly. */
2092
+ interface TypertRemoteContribution {
2093
+ /** npm package that owns the Remote methods. */
2094
+ readonly package: string;
2095
+ /** Consumer-side invocation descriptors generated from that package. */
2096
+ readonly descriptors: readonly InvocationDescriptor[];
2097
+ }
2098
+ /**
2099
+ * Resolve one validated wire identity, synchronously or asynchronously.
2100
+ * @param id - validated wire identity.
2101
+ * @returns the Host object, or `undefined` when unavailable.
2102
+ */
2103
+ type TypertLookupResolver<Host = unknown, Wire = unknown> = (id: Wire) => Host | undefined | Promise<Host | undefined>;
2104
+ /** Runtime provider for one declared Host object lookup. */
2105
+ interface TypertLookupProvider<Host = unknown, Wire = unknown> {
2106
+ /** Source parameter name recognized by the SRC weak parser. */
2107
+ readonly parameter: string;
2108
+ /** Wire field replacing the Host object parameter. */
2109
+ readonly wire: string;
2110
+ /** Canonical Host type symbol used by strict generation. */
2111
+ readonly hostTypeSymbol: string;
2112
+ /** Canonical wire type symbol used by strict generation. */
2113
+ readonly wireTypeSymbol: string;
2114
+ /**
2115
+ * Resolve a wire identity through the provider's default policy.
2116
+ * @param id - validated wire identity.
2117
+ * @returns the object, `undefined` when unavailable, or either asynchronously.
2118
+ */
2119
+ resolve(id: Wire): Host | undefined | Promise<Host | undefined>;
2120
+ }
2121
+ /** Stable wire declaration retained after a lookup provider unloads. */
2122
+ interface TypertLookupDefinition {
2123
+ /** Merge-declared lookup key. */
2124
+ readonly key: string;
2125
+ /** Source parameter name recognized by the SRC weak parser. */
2126
+ readonly parameter: string;
2127
+ /** Wire field replacing the Host object parameter. */
2128
+ readonly wire: string;
2129
+ /** Canonical Host type symbol used by strict generation. */
2130
+ readonly hostTypeSymbol: string;
2131
+ /** Canonical wire type symbol used by strict generation. */
2132
+ readonly wireTypeSymbol: string;
2133
+ }
2134
+ /** Host resolver for one scoped Remote kind. */
2135
+ interface TypertHostContextProvider<Wire = unknown> {
2136
+ /** Wire field carrying the Context identity. */
2137
+ readonly wire: string;
2138
+ /** Canonical wire type symbol used by strict generation. */
2139
+ readonly wireTypeSymbol: string;
2140
+ /**
2141
+ * Resolve a wire identity to its live scoped Context.
2142
+ * @param id - validated wire identity.
2143
+ * @returns the scoped Context, or `undefined` when unavailable.
2144
+ */
2145
+ resolve(id: Wire): Context | undefined | Promise<Context | undefined>;
2146
+ }
2147
+ /** Composition-owned resolver replacing one Host Context provider's default lookup policy. */
2148
+ type TypertHostContextResolver<Wire = unknown> = (id: Wire) => Context | undefined | Promise<Context | undefined>;
2149
+ /** Client resolver for the identity carried by the calling scoped Context. */
2150
+ interface TypertClientContextBinder<Wire = unknown> {
2151
+ /**
2152
+ * Read the Remote identity represented by a calling Context.
2153
+ * @param ctx - Context rebound by the Cordis service tracker.
2154
+ * @returns the wire identity, or `undefined` when the Context has the wrong scope.
2155
+ */
2156
+ identity(ctx: Context): Wire | undefined;
2157
+ }
2158
+ /** Notification emitted after a Typert runtime registry changes. */
2159
+ interface TypertRegistryChange {
2160
+ readonly kind: 'local' | 'remote' | 'lookup' | 'host-context' | 'client-context';
2161
+ readonly key: string;
2162
+ }
2163
+ /** Listener for one Typert runtime registry. */
2164
+ type TypertRegistryListener = (change: TypertRegistryChange) => void;
2165
+ /** Current-environment invocation definitions. */
2166
+ interface TypertLocalRegistry {
2167
+ /**
2168
+ * Look up one invocation by `<namespace>/<method>`.
2169
+ * @param endpoint - canonical endpoint.
2170
+ * @returns the live descriptor, or `undefined` when absent.
2171
+ */
2172
+ get(endpoint: string): InvocationDescriptor | undefined;
2173
+ /**
2174
+ * Report whether a strict definition has existed during this Typert Service lifetime.
2175
+ * @param endpoint - canonical endpoint.
2176
+ * @returns `true` after the endpoint has been registered at least once, even if withdrawn.
2177
+ */
2178
+ hasSeen(endpoint: string): boolean;
2179
+ /** @returns a registration-order snapshot of local descriptors. */
2180
+ list(): readonly InvocationDescriptor[];
2181
+ /**
2182
+ * Observe later local-definition changes.
2183
+ * @param listener - synchronous contained observer.
2184
+ * @returns disposer for this subscription.
2185
+ */
2186
+ subscribe(listener: TypertRegistryListener): TypertDisposer;
2187
+ }
2188
+ /** Consumer-selected Remote contribution registry. */
2189
+ interface TypertRemoteRegistry {
2190
+ /**
2191
+ * Register one generated contribution for the calling Cordis fiber.
2192
+ * @param contribution - generated Remote descriptors.
2193
+ * @returns disposer withdrawing the exact contribution.
2194
+ */
2195
+ register(contribution: TypertRemoteContribution): TypertDisposer;
2196
+ /**
2197
+ * Look up one Remote descriptor by endpoint.
2198
+ * @param endpoint - canonical endpoint.
2199
+ * @returns the descriptor, or `undefined` when unmounted.
2200
+ */
2201
+ get(endpoint: string): InvocationDescriptor | undefined;
2202
+ /** @returns a registration-order snapshot of Remote descriptors. */
2203
+ list(): readonly InvocationDescriptor[];
2204
+ /**
2205
+ * Observe later Remote contribution changes.
2206
+ * @param listener - synchronous contained observer.
2207
+ * @returns disposer for this subscription.
2208
+ */
2209
+ subscribe(listener: TypertRegistryListener): TypertDisposer;
2210
+ }
2211
+ /** Runtime registry for Host object lookup providers. */
2212
+ interface TypertLookupRegistry {
2213
+ /**
2214
+ * Register one provider under its merge-declared key.
2215
+ * @param key - lookup key.
2216
+ * @param provider - owning package's live resolver.
2217
+ * @returns disposer withdrawing the exact provider.
2218
+ */
2219
+ register<K extends StringKeyOf<TypertLookupMap>>(key: K, provider: TypertLookupProvider<TypertLookupHost<TypertLookupMap[K]>, TypertLookupWire<TypertLookupMap[K]>>): TypertDisposer;
2220
+ /**
2221
+ * Replace one provider's default resolution policy while this contribution is active.
2222
+ * Configuration may precede provider registration; without a live provider, `get()` remains unavailable.
2223
+ * @param key - lookup key whose wire declaration remains provider-owned.
2224
+ * @param resolver - composition-owned resolver used by every lookup of this key.
2225
+ * @returns disposer restoring the provider's default resolver.
2226
+ */
2227
+ configure<K extends StringKeyOf<TypertLookupMap>>(key: K, resolver: TypertLookupResolver<TypertLookupHost<TypertLookupMap[K]>, TypertLookupWire<TypertLookupMap[K]>>): TypertDisposer;
2228
+ /**
2229
+ * Look up one provider by runtime key.
2230
+ * @param key - descriptor lookup key.
2231
+ * @returns the live provider, or `undefined` when absent.
2232
+ */
2233
+ get(key: string): TypertLookupProvider | undefined;
2234
+ /** @returns lookup declarations observed during this Typert Service lifetime. */
2235
+ definitions(): readonly TypertLookupDefinition[];
2236
+ /** @returns a snapshot of registered provider keys. */
2237
+ keys(): readonly string[];
2238
+ /**
2239
+ * Observe later lookup changes.
2240
+ * @param listener - synchronous contained observer.
2241
+ * @returns disposer for this subscription.
2242
+ */
2243
+ subscribe(listener: TypertRegistryListener): TypertDisposer;
2244
+ }
2245
+ /** Runtime registry for Host Context resolvers and Client Context binders. */
2246
+ interface TypertContextRegistry {
2247
+ /**
2248
+ * Register a Host Context resolver.
2249
+ * @param key - merge-declared Context key.
2250
+ * @param provider - owning package's Host resolver.
2251
+ * @returns disposer withdrawing the exact provider.
2252
+ */
2253
+ registerHost<K extends StringKeyOf<TypertContextMap>>(key: K, provider: TypertHostContextProvider<TypertContextWire<TypertContextMap[K]>>): TypertDisposer;
2254
+ /**
2255
+ * Override one Host Context key's identity policy for the calling fiber.
2256
+ * Configuration may precede provider registration and restores the provider's default resolver on disposal.
2257
+ * @param key - merge-declared Context key.
2258
+ * @param resolver - composition-owned resolver used by every Host Context lookup of this key.
2259
+ * @returns disposer restoring the provider's default resolver.
2260
+ */
2261
+ configureHost<K extends StringKeyOf<TypertContextMap>>(key: K, resolver: TypertHostContextResolver<TypertContextWire<TypertContextMap[K]>>): TypertDisposer;
2262
+ /**
2263
+ * Register a Client Context identity binder.
2264
+ * @param key - merge-declared Context key.
2265
+ * @param binder - Client scope identity resolver.
2266
+ * @returns disposer withdrawing the exact binder.
2267
+ */
2268
+ registerClient<K extends StringKeyOf<TypertContextMap>>(key: K, binder: TypertClientContextBinder<TypertContextWire<TypertContextMap[K]>>): TypertDisposer;
2269
+ /**
2270
+ * Look up a Host Context resolver.
2271
+ * @param key - descriptor Context key.
2272
+ * @returns the provider, or `undefined` when absent.
2273
+ */
2274
+ getHost(key: string): TypertHostContextProvider | undefined;
2275
+ /**
2276
+ * Look up a Client Context binder.
2277
+ * @param key - descriptor Context key.
2278
+ * @returns the binder, or `undefined` when absent.
2279
+ */
2280
+ getClient(key: string): TypertClientContextBinder | undefined;
2281
+ /**
2282
+ * Observe later Context provider changes.
2283
+ * @param listener - synchronous contained observer.
2284
+ * @returns disposer for this subscription.
2285
+ */
2286
+ subscribe(listener: TypertRegistryListener): TypertDisposer;
2287
+ }
2288
+ /** Minimal Typert runtime consumed through dependency inversion. */
2289
+ interface TypertRegistryContract {
2290
+ readonly local: TypertLocalRegistry;
2291
+ readonly remotes: TypertRemoteRegistry;
2292
+ readonly lookups: TypertLookupRegistry;
2293
+ readonly contexts: TypertContextRegistry;
2294
+ }
2295
+ declare module '@deepseek-ai/cordis' {
2296
+ interface Context {
2297
+ typert: TypertRegistryContract;
2298
+ }
2299
+ }
2300
+ //#endregion
2301
+ //#region ../../node_modules/@deepseek-ai/dsh-session/lib/types/surface.d.ts
2302
+ /** Readonly live projection of the message-producing session events. */
2303
+ interface SessionSurface {
2304
+ /** Current surface event sequences in model-visible order. */
2305
+ readonly nodes: readonly number[];
2306
+ /** Monotonic count of committed positional replacements. */
2307
+ readonly replaceGeneration: number;
2308
+ }
2309
+ //#endregion
2310
+ //#region ../../node_modules/@deepseek-ai/dsh-session/lib/types/index.d.ts
2311
+ declare module '@deepseek-ai/cordis' {
2312
+ interface Context {
2313
+ sessions: SessionStore;
2314
+ }
2315
+ interface Events {
2316
+ /**
2317
+ * Creation announcement during session publication. A synchronous throw vetoes and rolls
2318
+ * back with a paired disposal; detach requested during dispatch is deferred.
2319
+ * A returned-promise rejection is logged but cannot retroactively veto this
2320
+ * synchronous boundary.
2321
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners
2322
+ * receive only sessions entered through that agent's context.
2323
+ * @param session - the session just entered and announced.
2324
+ * @dshScopeScan unsupported
2325
+ * @mode emit
2326
+ */
2327
+ 'session/created'(this: Scoped<Session>, session: Session): void;
2328
+ /**
2329
+ * Emitted once when an announced session leaves the store, including
2330
+ * publication rollback, but never for an entry whose creation announcement
2331
+ * did not begin. Listener failures are logged and contained.
2332
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`) reuses the owner scope.
2333
+ * @param session - the session that is no longer live in the store.
2334
+ * @dshScopeScan unsupported
2335
+ * @mode emit
2336
+ */
2337
+ 'session/disposed'(this: Scoped<Session>, session: Session): void;
2338
+ /**
2339
+ * Post-commit, fire-and-forget append feed. The listener snapshot resolves
2340
+ * before the log push, but callbacks run after it; observer failures are
2341
+ * logged and contained without making the committed append fail.
2342
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners
2343
+ * receive only events from sessions entered through that agent's context.
2344
+ * @param session - the session whose log grew.
2345
+ * @param event - the appended event, exactly as recorded.
2346
+ * @dshScopeScan unsupported
2347
+ * @mode emit
2348
+ */
2349
+ 'session/event'(this: Scoped<Session>, session: Session, event: SessionEvent): void;
2350
+ /**
2351
+ * Awaited parallel durability checkpoint: every listener runs and the
2352
+ * caller awaits all of them, with no waterfall veto. Scope-filtered dispatch
2353
+ * (`@deepseek-ai/dsh-scope`) reuses the session's owner scope.
2354
+ * @param session - the session whose buffered events must reach durable storage.
2355
+ * @dshScopeScan unsupported
2356
+ * @mode parallel
2357
+ */
2358
+ 'session/flush'(this: Scoped<Session>, session: Session): Promise<void> | void;
2359
+ }
2360
+ }
2361
+ declare module '@deepseek-ai/dsh-typert-protocol' {
2362
+ interface TypertLookupMap {
2363
+ session: TypertLookup<Session, SessionId>;
2364
+ }
2365
+ }
2366
+ /**
2367
+ * An event-sourced session: an append-only log of {@link SessionEvent}s.
2368
+ *
2369
+ * Plain class (not a Service) — create live instances via
2370
+ * `ctx.sessions.create()` and detached instances via {@link create}.
2371
+ * Seeding with an existing event log replays/forks a session.
2372
+ * @typert object
2373
+ */
2374
+ declare class Session {
2375
+ private log;
2376
+ /** Single incremental owner of surface acceptance and projection state. */
2377
+ private readonly surfaceManager;
2378
+ /** The ordered surface over this session's event log. */
2379
+ get surface(): SessionSurface;
2380
+ /**
2381
+ * Detached, deep-frozen creation metadata (format version, cwd, lineage,
2382
+ * seed boundary). Supplied by the store via `ctx.sessions.create()`. When a
2383
+ * `Session` is created without a store-owned header, a minimal header is
2384
+ * synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so
2385
+ * `session.header` is always present. Kept out of the event log — it is a
2386
+ * storage concern, not replayable conversation state.
2387
+ */
2388
+ readonly header: SessionHeader;
2389
+ /** The session identity, derived from its durable header's single copy. */
2390
+ get id(): SessionId;
2391
+ /**
2392
+ * The first seq appended IN THIS PROCESS: the length of the constructor
2393
+ * seed (0 without one). Events with smaller seq values entered through
2394
+ * construction — replay, fork, or resume — and were never published on the
2395
+ * `session/event` firehose (constructor seeds do not emit), so consumers
2396
+ * that replay the log as a publication substitute (telemetry adoption)
2397
+ * start here. Distinct from `header.seedLength`, the DURABLE fork-lineage
2398
+ * boundary: a resumed session's constructor seed is its full stored log,
2399
+ * while its header keeps the original fork value — this field is the
2400
+ * in-process construction fact.
2401
+ *
2402
+ * Not persisted itself: a seeded session projects it into the log as the
2403
+ * `session/end-seed` event, which is what a consumer reading STORED history
2404
+ * reads. Locate the LAST such event, not necessarily one at this seq — a
2405
+ * seed already ending in one is not re-marked, so reopening an untouched
2406
+ * session leaves that event at a smaller seq than `firstLiveSeq`. Prefer
2407
+ * this field in-process: it is exact before the marker reaches storage.
2408
+ *
2409
+ * When this lifecycle appends the marker, it occupies this seq before the
2410
+ * store attaches and therefore does not publish either. Otherwise this seq
2411
+ * holds an ordinary published write.
2412
+ */
2413
+ readonly firstLiveSeq: number;
2414
+ /**
2415
+ * Create a detached session by validating and snapshotting borrowed seed
2416
+ * events and storage metadata.
2417
+ * @param id - session identity.
2418
+ * @param seed - optional borrowed replay or fork events.
2419
+ * @param header - optional borrowed storage metadata.
2420
+ * @returns a detached session.
2421
+ */
2422
+ static create(id: SessionId, seed?: readonly SessionEvent[], header?: SessionHeader): Session;
2423
+ /**
2424
+ * Restore a detached session by taking ownership of fresh persistence values.
2425
+ * The storage format, event envelopes, sequence continuity, surface transitions,
2426
+ * and header fields are validated before the restored objects are frozen.
2427
+ * @param id - restored session identity.
2428
+ * @param seed - fresh detached events whose ownership is transferred.
2429
+ * @param header - fresh detached metadata whose ownership is transferred.
2430
+ * @returns a restored detached session.
2431
+ */
2432
+ static fromRestore(id: SessionId, seed: readonly SessionEvent[], header: SessionHeader): Session;
2433
+ private constructor();
2434
+ /** Cached immutable public snapshot of the private append-only log. */
2435
+ private eventsSnapshot;
2436
+ /**
2437
+ * An immutable snapshot of the append-only event log. The snapshot is reused
2438
+ * until the next append; a previously returned array does not grow later.
2439
+ * Events and their nested data are deep-frozen at acceptance, so neither a
2440
+ * cast nor ordinary JavaScript can rewrite durable history.
2441
+ */
2442
+ get events(): readonly SessionEvent[];
2443
+ /** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */
2444
+ get seq(): number;
2445
+ /**
2446
+ * Append one typed event to the log and synchronously notify observers via
2447
+ * the store-owned, module-private publication hooks. The hot path never blocks
2448
+ * on I/O — persistence plugins buffer asynchronously. Once the event enters
2449
+ * the log, the append is committed: observer failures are logged and
2450
+ * contained per listener, so they do not change the return value or prevent
2451
+ * later listeners from observing the same accepted event.
2452
+ *
2453
+ * @param type - The event type (key of {@link SessionEventMap}).
2454
+ * @param data - The event payload; must be JSON-serializable.
2455
+ * @param opts - Surface metadata: `surfaceOp` controls how the event enters
2456
+ * the ordered surface; `sourceEventSeqs` lists the seq numbers of earlier
2457
+ * events this one derives from. REQUIRED for
2458
+ * {@link SurfaceEventType} events (every message-producing event must
2459
+ * declare how it joins the surface, the sole source of derived model
2460
+ * history) and
2461
+ * rejected by the compiler for non-surface types like `turn/start` or
2462
+ * `assistant/chunk`.
2463
+ * @returns the logged event — its assigned `seq`/`time` plus the SNAPSHOT of
2464
+ * `data` that entered the log, so reading `event.data` back sees the logged
2465
+ * value, never the caller's still-mutable input.
2466
+ * @throws if `data` or surface metadata is not losslessly JSON-serializable
2467
+ * (BigInt, function, symbol, undefined, negative zero, non-finite number,
2468
+ * circular reference, sparse array, or an exotic object such as
2469
+ * Map/Set/Date/class instance), or when the candidate violates the
2470
+ * canonical surface contract (marker shape and eligibility, unique
2471
+ * earlier source-event references, positional replacement validity, and complete
2472
+ * shadowed-node coverage). One recursive pass reads, validates, and
2473
+ * copies each nested value once, so a stateful getter cannot supply one value
2474
+ * to validation and another to storage. The event log is the durable source
2475
+ * of truth, so a bad event fails at the append site rather than later during
2476
+ * a backend flush. A synchronous internal dispatch validation failure or an
2477
+ * append reentered while this acceptance/publication boundary is open also
2478
+ * rejects before the log changes.
2479
+ */
2480
+ append<T extends SessionEventType>(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : []): SessionEvent<T>;
2481
+ /** Cached fold of the request-header events — see {@link requestHeader}. */
2482
+ private headerFold;
2483
+ /** Log position (events consumed) the header fold has reached. */
2484
+ private headerFoldSeq;
2485
+ /**
2486
+ * The {@link EpochHeader} in force after the log's last header event — the
2487
+ * header the NEXT request will be compared against — or undefined before
2488
+ * the first `request/header` snapshot. The live, incrementally-maintained
2489
+ * form of `foldRequestHeader(session.events)`: each header event is folded
2490
+ * once, when first seen, so a per-step read costs O(new events).
2491
+ * @returns the folded header, or undefined when no header event exists yet.
2492
+ */
2493
+ requestHeader(): EpochHeader | undefined;
2494
+ /** Cached fold of `request/context` events. */
2495
+ private contextFold;
2496
+ private contextFoldSeq;
2497
+ /**
2498
+ * Return the latest resolved route metadata, or `undefined` before the first
2499
+ * `request/context` event. Each event is folded once.
2500
+ * @returns the latest immutable route metadata.
2501
+ */
2502
+ requestContext(): RequestContext | undefined;
2503
+ /** The derived-message cache: frozen projections, extended per unseen node. */
2504
+ private derived;
2505
+ /** Surface position (nodes projected) the cache has reached. */
2506
+ private derivedNodes;
2507
+ /** {@link SurfaceManager.replaceGeneration} the cache was built under. */
2508
+ private derivedGeneration;
2509
+ /**
2510
+ * Derive the LLM message history by walking the ordered sequences of
2511
+ * message-producing events maintained by `surfaceOp` markers. The
2512
+ * surface is the single source of derived history: every message-producing
2513
+ * append records its `surfaceOp`, so a raw event with no marker (a chunk, a
2514
+ * turn boundary) is correctly absent, and a compaction `replace` deletes the
2515
+ * shadowed nodes from the derivation. The projection rules are
2516
+ * {@link deriveEventMessage}, folded per node.
2517
+ *
2518
+ * CACHED: each surface node is projected exactly once, when first seen — a
2519
+ * call costs O(new nodes), and a surface rewrite (a `replace`;
2520
+ * {@link SessionSurface.replaceGeneration}) rebuilds. The returned array is
2521
+ * a fresh snapshot per call (later appends never grow an array a caller
2522
+ * already holds); the `Message` objects in it are SHARED and **deep-frozen**.
2523
+ * Their content reuses the already frozen durable event data, so the cache
2524
+ * needs no second deep clone and consumers still cannot mutate the log.
2525
+ * @returns a fresh array of the shared, frozen derived history.
2526
+ */
2527
+ deriveMessages(): Message[];
2528
+ /**
2529
+ * Instance face of the pure per-node `deriveEventMessage` export from
2530
+ * `surface.ts`.
2531
+ * @param event - the event to project.
2532
+ * @returns the derived message, or null when the event produces none.
2533
+ */
2534
+ deriveEventMessage(event: SessionEvent): Message | null;
2535
+ }
2536
+ /** A fork source: either the live session object or its live store id. */
2537
+ type SessionForkSource = Session | SessionId;
2538
+ /**
2539
+ * In-memory session store (`ctx.sessions`).
2540
+ *
2541
+ * Persistence is intentionally not implemented here — persistence plugins
2542
+ * subscribe to `session/event` and flush on `session/flush` / dispose.
2543
+ */
2544
+ declare class SessionStore extends Service {
2545
+ private store;
2546
+ private counter;
2547
+ constructor(ctx: Context);
2548
+ /**
2549
+ * Create a session owned by the calling fiber: disposing that fiber stops
2550
+ * event notification and removes the session from the store. `options.seed`
2551
+ * populates the session with a copy of those events (replay/fork);
2552
+ * `options.meta` attaches creation metadata (validated absolute `cwd`, seed
2553
+ * and parent lineage, and delegation depth) as the immutable
2554
+ * {@link SessionHeader} (the store fills `version`/`id`/`createdAt`).
2555
+ *
2556
+ * For an agent whose session must be torn down IN ORDER with its loop (so the
2557
+ * loop's final events are published before the store attachment ends), do NOT use this
2558
+ * — fold the session lifecycle into the agent's own effect via
2559
+ * {@link prepare} + {@link enter} + {@link announce} (see
2560
+ * `dsh-agent-loop`'s creation transaction).
2561
+ *
2562
+ * @param id - the session id; omitted, the store mints `session-<n>`.
2563
+ * @param options - seed events and/or creation metadata for the header.
2564
+ * @returns the live session, already entered and announced.
2565
+ * @throws if a session with `id` already exists, metadata is not a plain
2566
+ * lossless-JSON record with valid scalar fields, or `meta.cwd` is a
2567
+ * non-absolute path (storage backends key directories off it).
2568
+ */
2569
+ create(id?: SessionId, options?: CreateSessionOptions): Session;
2570
+ /**
2571
+ * Build a session WITHOUT entering it into the store — validate the id/cwd and
2572
+ * construct the {@link Session} (with its immutable {@link SessionHeader}).
2573
+ * Pairs with {@link enter} + {@link announce}: a caller that owns a composite
2574
+ * `ctx.effect` (the agent factory) folds the session lifecycle into that ONE
2575
+ * effect so a fiber unload tears the session + agent down as a single ORDERED
2576
+ * chain rather than as racing sibling effects — which would remove the publication hooks
2577
+ * before the driver's closing events commit, dropping them.
2578
+ *
2579
+ * @param id - the session id; omitted, the store mints `session-<n>`.
2580
+ * @param options - seed events and/or creation metadata for the header. With
2581
+ * `seedSource: 'persistence'`, metadata and events must be fresh detached
2582
+ * graphs whose ownership transfers to this call: they are validated and
2583
+ * frozen in place through {@link Session.fromRestore}, so the caller must
2584
+ * retain no mutable aliases.
2585
+ * @returns the constructed session, NOT yet in the store.
2586
+ * @throws if a session with `id` already exists, metadata is not a plain
2587
+ * lossless-JSON record with valid scalar fields, or `meta.cwd` is a
2588
+ * non-absolute path.
2589
+ */
2590
+ prepare(id?: SessionId, options?: PrepareSessionOptions): Session;
2591
+ /**
2592
+ * Enter a {@link prepare}d session into the store: install the module-private
2593
+ * append publication hooks and add it to the store. Returns the DETACH
2594
+ * disposer (hooks + store removal). Does NOT emit `session/created` —
2595
+ * the caller yields this disposer inside its effect and THEN calls
2596
+ * {@link announce}, so a throwing `session/created` listener rolls the attach
2597
+ * back instead of leaking it.
2598
+ *
2599
+ * Re-checks the id for a duplicate: `prepare` and `enter` are public
2600
+ * cross-package primitives and a caller may interleave arbitrary work (or
2601
+ * another create) between them, so a stale prepared session must NOT overwrite
2602
+ * a live store entry of the same id — its detach disposer would later delete
2603
+ * the REAL session. The {@link create} convenience and the agent factory call
2604
+ * the two back-to-back so they never trip this, but the public API cannot
2605
+ * assume that.
2606
+ *
2607
+ * @param session - a {@link prepare}d session not yet in the store.
2608
+ * @returns the detach disposer (publication hooks + store removal). When called from
2609
+ * a synchronous `session/created` listener, removal and disposal wait until
2610
+ * that creation dispatch unwinds.
2611
+ * @throws if a session with this id is already in the store.
2612
+ */
2613
+ enter(session: Session): () => void;
2614
+ /** Remove one exact entered session and emit its paired disposal when announced. */
2615
+ private detachEntered;
2616
+ /** Emit `session/created` exactly once for an {@link enter}ed session (with
2617
+ * the carrier {@link enter} captured). Separate from {@link enter} so the
2618
+ * caller can yield the detach disposer first (rollback safety — see
2619
+ * {@link enter}).
2620
+ * @param session - the entered session to announce to listeners.
2621
+ * @throws if the session is not live or its announcement already began,
2622
+ * including a reentrant call from a creation listener. */
2623
+ announce(session: Session): void;
2624
+ /** Emit the paired teardown notification with per-listener containment. */
2625
+ private emitDisposed;
2626
+ /**
2627
+ * Dispatch the awaited `session/flush` durability checkpoint for `session`,
2628
+ * with the carrier captured at {@link enter}. THE flush entry point: the
2629
+ * store owns the carrier, so callers (the checkpoint policy's per-request
2630
+ * barrier, goal-round-driver's idle checkpoint, teardown drains, and consumers
2631
+ * that flush themselves before reading storage) must come through here
2632
+ * rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner,
2633
+ * one spelling, and the scoped-dispatch invariant can pin it.
2634
+ * @param session - the session whose buffered events must reach durable storage.
2635
+ * @returns whether at least one durability listener participated, after every
2636
+ * listener has settled successfully.
2637
+ * @throws the first registered listener failure after every listener settles.
2638
+ */
2639
+ flush(session: Session): Promise<boolean>;
2640
+ /** Return the exact live entry; detached/prepared objects reject. */
2641
+ private liveEntryFor;
2642
+ /**
2643
+ * Look up a live session.
2644
+ * @param id - the session id to look up.
2645
+ * @returns the session, or undefined when no live session has that id.
2646
+ */
2647
+ get(id: SessionId): Session | undefined;
2648
+ /**
2649
+ * All live sessions, in creation order.
2650
+ * @returns a fresh array; mutating it does not affect the store.
2651
+ */
2652
+ list(): Session[];
2653
+ /**
2654
+ * Create a live child session from a stable prefix of a live source.
2655
+ * `boundary` is an inclusive source event seq; omitted means the source's
2656
+ * current last event. The selected slice may end with a between-turn event
2657
+ * but must not end inside an open turn.
2658
+ *
2659
+ * @param source - Live source session object or id.
2660
+ * @param boundary - Inclusive source event seq to fork through; omitted means
2661
+ * the source's current last event, and omitted on an empty source forks an
2662
+ * empty child.
2663
+ * @param childSessionId - Optional child session id; omitted delegates to
2664
+ * `SessionStore`'s id policy.
2665
+ * @returns The created live child session.
2666
+ */
2667
+ fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId): Session;
2668
+ private _forkSeed;
2669
+ private _resolveForkSource;
2670
+ }
2671
+ //#endregion
2672
+ //#region ../../node_modules/@deepseek-ai/dsh-sandbox/lib/types/index.d.ts
2673
+ /**
2674
+ * File-effect policy for confined processes. `read-only` permits only required
2675
+ * sinks such as `/dev/null`; `workspace-write` also permits the workspace and a
2676
+ * backend-defined temp area; `danger-full-access` bypasses confinement. Network
2677
+ * and process visibility are outside this vocabulary.
2678
+ */
2679
+ type SandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access';
2680
+ /** A confining (non-`danger-full-access`) mode — the modes a {@link SandboxPolicy} can carry. */
2681
+ type ConfinedSandboxMode = Exclude<SandboxMode, 'danger-full-access'>;
2682
+ /**
2683
+ * The complete file-effect policy resolved for one capability call. The root
2684
+ * is carried even under modes that do not consume it so callers can resolve
2685
+ * policy once before choosing the enforcement path.
2686
+ */
2687
+ interface SandboxExecutionPolicy {
2688
+ /** The file-effect mode this execution runs under. */
2689
+ mode: SandboxMode;
2690
+ /** Absolute root directory `workspace-write` may write under. */
2691
+ workspaceRoot: string;
2692
+ /**
2693
+ * Opaque identity of the calling session (the branded `dsh-session`
2694
+ * SessionId). Backends key per-session state off it (e.g. windows-acl gives
2695
+ * each live session/workspace pair a random private temp directory and SID,
2696
+ * while the workspace SID and standing grant remain per-workspace); absent
2697
+ * for agentless calls, which fall back to per-call backend state.
2698
+ */
2699
+ sessionId?: SessionId;
2700
+ }
2701
+ /**
2702
+ * Enforcement completeness for this host. `partial` means an active backend or
2703
+ * older kernel ABI cannot govern every promised file effect; callers requiring
2704
+ * an absolute boundary must not treat it as `full`.
2705
+ */
2706
+ type SandboxEnforcement = 'full' | 'partial';
2707
+ /**
2708
+ * What one confined execution is allowed to touch — carried PER CALL, not
2709
+ * fixed on the provider: two consumers may confine under different policies
2710
+ * at the same instant (bash under `read-only` while a confined child agent
2711
+ * needs its state directory writable), and an approved escalated retry is a
2712
+ * new call with a wider policy. Defaulting/resolution is an explicit step at
2713
+ * the consumer boundary; the provider treats the policy as fully specified.
2714
+ */
2715
+ interface SandboxPolicy extends SandboxExecutionPolicy {
2716
+ /** The file-effect mode this execution runs under. */
2717
+ mode: ConfinedSandboxMode;
2718
+ }
2719
+ /**
2720
+ * Evidence that identifies a sandbox runner failing before it executes the
2721
+ * wrapped command. A consumer first applies {@link allowedExitCodes} when
2722
+ * present, removes {@link informationalLines} by case-insensitive exact line
2723
+ * equality, then matches {@link fatalSignatures} case-insensitively within
2724
+ * each remaining stderr line. Exit status alone never proves runner failure.
2725
+ */
2726
+ interface RunnerFailureRule {
2727
+ /** Nonzero process exit codes on which this rule may match; omitted permits any nonzero exit. */
2728
+ allowedExitCodes?: readonly number[];
2729
+ /** Non-empty substrings identifying a fatal runner diagnostic on one stderr line. */
2730
+ fatalSignatures: readonly string[];
2731
+ /** Benign stderr lines excluded by exact full-line equality before fatal matching. */
2732
+ informationalLines?: readonly string[];
2733
+ }
2734
+ /**
2735
+ * A {@link SandboxProvider.confine} result: the argv to spawn in place of
2736
+ * the caller's own, plus the enforcement completeness the selected backend
2737
+ * achieves for it.
2738
+ */
2739
+ interface ConfinedArgv {
2740
+ /** The wrapped argv (runner, profile, separator, then the caller's argv). */
2741
+ argv: string[];
2742
+ /** How completely the selected backend enforces the policy's file effects. */
2743
+ enforcement: SandboxEnforcement;
2744
+ /**
2745
+ * The selected backend's denial DIALECT: the case-insensitive stderr
2746
+ * substrings a file effect denied by THIS backend produces (EROFS text
2747
+ * under bwrap's read-only binds, EACCES under Landlock, EPERM under
2748
+ * Seatbelt). A consumer that infers denials from a failed run's stderr
2749
+ * matches against exactly these rather than a cross-backend union — the
2750
+ * union claims denials a given backend never produces.
2751
+ */
2752
+ denialSignatures: readonly string[];
2753
+ /**
2754
+ * Structured runner-failure evidence rules. Consumers require a matching
2755
+ * fatal stderr line (after informational exclusions) and any rule-specific
2756
+ * exit-code gate before checking denial signatures: runner failure means the
2757
+ * command never ran, while denial means confinement worked and blocked it.
2758
+ */
2759
+ runnerFailureRules: readonly RunnerFailureRule[];
2760
+ }
2761
+ declare module '@deepseek-ai/cordis' {
2762
+ interface Context {
2763
+ sandbox: SandboxProvider;
2764
+ }
2765
+ }
2766
+ /**
2767
+ * Abstract process-sandbox service. {@link confine} must return enforcing argv
2768
+ * or fail closed at wrap or runner-execution time; silent unconfined passthrough
2769
+ * is forbidden. Functional probes arbitrate multi-runner chains and may be
2770
+ * skipped for a sole candidate, whose own refusal remains the fail-closed end.
2771
+ */
2772
+ declare abstract class SandboxProvider extends Service {
2773
+ constructor(ctx: Context);
2774
+ /**
2775
+ * Wrap `argv` so it executes confined under `policy` on this host; the
2776
+ * caller spawns the returned argv in place of its own.
2777
+ * @param argv - the exact argv the caller is about to spawn (program plus
2778
+ * arguments), NOT a shell string — a shell-shaped consumer passes
2779
+ * `['bash', '-c', command]`.
2780
+ * @param policy - the file-effect policy this execution runs under,
2781
+ * carried per call (see {@link SandboxPolicy}).
2782
+ * @returns the argv to spawn instead, plus the enforcement completeness
2783
+ * the selected backend achieves for it.
2784
+ */
2785
+ abstract confine(argv: readonly string[], policy: SandboxPolicy): ConfinedArgv;
2786
+ }
2787
+ //#endregion
2788
+ //#region ../../node_modules/@deepseek-ai/dsh-subprocess/lib/types/types.d.ts
2789
+ /** Namespace prefix reserved for DeepSeek Harness-managed child environment facts. */
2790
+ declare const DSH_ENV_PREFIX: "DSH_";
2791
+ /** One environment key inside the managed {@link DSH_ENV_PREFIX} namespace. */
2792
+ type DshEnvironmentKey = `${typeof DSH_ENV_PREFIX}${string}`;
2793
+ /** Trusted DeepSeek Harness variables for one child-process execution. */
2794
+ type DshEnvironment = Readonly<Record<DshEnvironmentKey, string>>;
2795
+ /** One captured stream: the (possibly truncated) text plus recovery info. */
2796
+ interface CollectedOutput {
2797
+ /** Collected text — the TAIL of the stream when truncated. */
2798
+ text: string;
2799
+ /** True when bytes were dropped from `text`. */
2800
+ truncated: boolean;
2801
+ /** Path to a file holding the COMPLETE stream, when truncated and available. */
2802
+ spillPath?: string;
2803
+ }
2804
+ /**
2805
+ * stdin disposition. `'ignore'` leaves fd 0 on `/dev/null`; `'pipe'` exposes
2806
+ * {@link SubprocessHandle.stdin} for the caller's ongoing protocol writes;
2807
+ * `{ data }` writes the bytes and closes (the batch shape).
2808
+ */
2809
+ type SubprocessStdinMode = 'ignore' | 'pipe' | {
2810
+ readonly data: string;
2811
+ };
2812
+ /**
2813
+ * Bounded in-memory collection for one output stream, with an optional
2814
+ * full-stream spill file. Omitting `spill` keeps only the in-memory tail —
2815
+ * the diagnostic-tail shape (a language server's stderr); including it makes
2816
+ * the complete stream recoverable up to its cap (the bash tool shape).
2817
+ */
2818
+ interface SubprocessCollect {
2819
+ /** In-memory cap in bytes; overflow keeps the TAIL. */
2820
+ maxBytes: number;
2821
+ /** Full-stream spill file; absent disables spilling entirely. */
2822
+ spill?: {
2823
+ /** Whole-stream byte cap; a larger stream discards its now-incomplete spill. */
2824
+ maxBytes: number;
2825
+ };
2826
+ }
2827
+ /**
2828
+ * stdout/stderr disposition. `'pipe'` exposes the raw `Readable` for the
2829
+ * caller's protocol decoding; `'inherit'` passes the parent's descriptor
2830
+ * through (child diagnostics land on the harness's own stream); a
2831
+ * {@link SubprocessCollect} object buffers boundedly with offset-based reads.
2832
+ */
2833
+ type SubprocessOutputMode = 'pipe' | 'inherit' | SubprocessCollect;
2834
+ /** Per-stream stdio dispositions, all explicit — this seam applies no defaults. */
2835
+ interface SubprocessStdio {
2836
+ stdin: SubprocessStdinMode;
2837
+ stdout: SubprocessOutputMode;
2838
+ stderr: SubprocessOutputMode;
2839
+ }
2840
+ /**
2841
+ * A fully-specified spawn request. This seam applies no defaults: every
2842
+ * disposition, limit, and directory is explicit, so the caller's own config —
2843
+ * not a hidden subprocess-service default — decides them (the `dsh-shell`
2844
+ * request/spec split is the owning template).
2845
+ */
2846
+ interface SubprocessSpawnSpec {
2847
+ /** Executable and arguments; `argv[0]` is the program. Never shell-interpreted here. */
2848
+ argv: readonly string[];
2849
+ /** Working directory for the child. */
2850
+ cwd: string;
2851
+ /** Per-stream stdio dispositions. */
2852
+ stdio: SubprocessStdio;
2853
+ /**
2854
+ * Positive finite grace period in milliseconds, no greater than
2855
+ * `MAX_TIMER_DELAY_MS`, for the {@link SubprocessHandle.terminate} escalation
2856
+ * and for draining still-open collected pipes after the process exits (an
2857
+ * inherited descriptor held by a surviving descendant cannot hold the
2858
+ * outcome open indefinitely).
2859
+ */
2860
+ graceMs: number;
2861
+ /**
2862
+ * Abort signal — starts the terminate escalation on the process tree when
2863
+ * it fires. The caller owns deadlines and cause classification; this seam
2864
+ * only reacts to the abort.
2865
+ */
2866
+ signal?: AbortSignal | undefined;
2867
+ /**
2868
+ * Explicit environment entries merged onto the implementation's scrubbed
2869
+ * parent base (see `scrubbedParentEnv`), with no namespace validation. A
2870
+ * string is a deliberate caller opt-in, so a forwarded credential-shaped
2871
+ * entry or current `DSH_*` fact survives the scrub; `undefined` is a
2872
+ * tombstone that removes an ordinary ambient entry from the child.
2873
+ */
2874
+ env?: NodeJS.ProcessEnv | undefined;
2875
+ }
2876
+ /**
2877
+ * Exit facts of one closed process — Node's `close`-event vocabulary.
2878
+ * Deliberately carries NO timeout or cancellation classification (the caller
2879
+ * reads the signal it owns to classify causes) and NO output: collected
2880
+ * streams stay readable through {@link SubprocessHandle.collected} after
2881
+ * settlement, so batch and streaming callers share one access path.
2882
+ */
2883
+ interface SubprocessOutcome {
2884
+ /** Exit code; null when the process died from a signal. */
2885
+ exitCode: number | null;
2886
+ /** Terminating signal (e.g. 'SIGTERM'); null on normal exit. */
2887
+ signal: NodeJS.Signals | null;
2888
+ }
2889
+ /** One incremental {@link SubprocessOutputReader.readFrom} read. */
2890
+ interface SubprocessOutputRead {
2891
+ /** Stream text from the requested offset (the whole retained tail when lossy). */
2892
+ text: string;
2893
+ /** Whole-stream offset to resume from on the next read. */
2894
+ nextOffset: number;
2895
+ /** True when the requested offset slid out of the in-memory tail window. */
2896
+ lossy: boolean;
2897
+ /** Path to the full-stream spill file, when one was created and remains intact. */
2898
+ spillPath?: string;
2899
+ }
2900
+ /**
2901
+ * Cursor-free incremental access to one collected output stream. Offsets are
2902
+ * whole-stream byte coordinates owned by the caller, so independent readers
2903
+ * cannot consume one another's output; `readFrom(0)` after settlement is the
2904
+ * batch result (`lossy` then means the in-memory tail lost its head — the
2905
+ * {@link CollectedOutput.truncated} fact).
2906
+ */
2907
+ interface SubprocessOutputReader {
2908
+ /**
2909
+ * Read everything captured since `fromByte`. When that offset has slid out
2910
+ * of the in-memory tail window the read is `lossy` — it returns the whole
2911
+ * retained tail and the gap is only recoverable from the spill file.
2912
+ * @param fromByte - whole-stream offset to resume from (a prior read's `nextOffset`; 0 for the first read).
2913
+ * @returns the delta text, the next offset, the `lossy` flag, and the spill path when one exists.
2914
+ */
2915
+ readFrom(fromByte: number): SubprocessOutputRead;
2916
+ }
2917
+ /** Offset-based readers for the streams spawned in collect mode. */
2918
+ interface SubprocessCollectedOutputs {
2919
+ /** Present iff stdout is a {@link SubprocessCollect}. */
2920
+ readonly stdout?: SubprocessOutputReader;
2921
+ /** Present iff stderr is a {@link SubprocessCollect}. */
2922
+ readonly stderr?: SubprocessOutputReader;
2923
+ }
2924
+ /**
2925
+ * A live child process rooted in its own process tree. Collected output
2926
+ * remains readable after exit; piped streams belong to the caller.
2927
+ *
2928
+ * Termination is tree-scoped everywhere: POSIX signals the detached process
2929
+ * group (falling back to the direct child when the group is gone), Windows
2930
+ * terminates the tree via `taskkill /T`, so helper processes cannot outlive
2931
+ * the handle unnoticed.
2932
+ */
2933
+ interface SubprocessHandle {
2934
+ /** Process id (tree root); -1 when the spawn itself failed. */
2935
+ readonly pid: number;
2936
+ /** The child's stdin, present iff spawned with `stdin: 'pipe'`. */
2937
+ readonly stdin: Writable | undefined;
2938
+ /** The child's raw stdout, present iff spawned with `stdout: 'pipe'`. */
2939
+ readonly stdout: Readable | undefined;
2940
+ /** The child's raw stderr, present iff spawned with `stderr: 'pipe'`. */
2941
+ readonly stderr: Readable | undefined;
2942
+ /** Offset-based readers for collect-mode streams (also readable after exit). */
2943
+ readonly collected: SubprocessCollectedOutputs;
2944
+ /** Resolves at process close with exit facts; rejects only for spawn-level failures. */
2945
+ readonly done: Promise<SubprocessOutcome>;
2946
+ /**
2947
+ * Begin the SIGTERM → `graceMs` → SIGKILL escalation on the process tree
2948
+ * (Windows force-terminates immediately) — the seam's only termination
2949
+ * verb. Idempotent, a no-op once the tree is gone (the pid may be reused),
2950
+ * and also triggered by the spec's abort signal.
2951
+ */
2952
+ terminate(): void;
2953
+ /**
2954
+ * Wait until the process tree has exited — the tree, not just the direct
2955
+ * child, so a still-running helper is observable before teardown returns.
2956
+ * @param signal - optional bound for the wait.
2957
+ * @returns `true` when the tree exited, `false` when the signal aborted first.
2958
+ */
2959
+ waitForExit(signal?: AbortSignal): Promise<boolean>;
2960
+ }
2961
+ /**
2962
+ * Signals supported by the terminal-process primitive. Kept member-identical
2963
+ * to `TerminalSignal` in `@deepseek-ai/dsh-terminal` without a cross-seam dependency;
2964
+ * change both together.
2965
+ */
2966
+ type SubprocessTerminalSignal = 'SIGINT' | 'SIGTERM' | 'SIGKILL' | 'SIGTSTP' | 'SIGHUP';
2967
+ /** A fully specified terminal-process spawn. */
2968
+ interface SubprocessTerminalSpawnSpec {
2969
+ /** Executable and arguments; `argv[0]` is the program. */
2970
+ argv: readonly string[];
2971
+ /** Working directory in this subprocess provider's execution world. */
2972
+ cwd: string;
2973
+ /** Explicit environment layered after the provider's ambient scrub. */
2974
+ env?: Record<string, string> | undefined;
2975
+ /** Initial terminal row count. */
2976
+ rows: number;
2977
+ /** Initial terminal column count. */
2978
+ cols: number;
2979
+ /** TERM-to-KILL cleanup grace for the complete terminal session. */
2980
+ graceMs: number;
2981
+ /** Cancellation of terminal allocation; a published handle owns its later lifetime. */
2982
+ signal?: AbortSignal | undefined;
2983
+ }
2984
+ /** Current foreground process-group facts for one terminal. */
2985
+ interface SubprocessTerminalForeground {
2986
+ /** Foreground process-group id published by the terminal driver. */
2987
+ processGroupId: number;
2988
+ /** Whether the provider can currently prove that group is waiting on terminal input. */
2989
+ inputWaiting: boolean;
2990
+ }
2991
+ /**
2992
+ * One live terminal process and its owned OS session. Terminal allocation,
2993
+ * foreground-group inspection/signalling, and session-tree cleanup are one
2994
+ * deep subprocess primitive because none can be reconstructed from ordinary
2995
+ * piped stdio without substrate-specific process control.
2996
+ */
2997
+ interface SubprocessTerminalHandle {
2998
+ /** Top-level terminal process id. */
2999
+ readonly pid: number;
3000
+ /** UTF-8 terminal output bytes in delivery order; ends after queued output when the terminal exits. */
3001
+ readonly output: Readable;
3002
+ /** Resolves when the top-level process exits; rejects only for a live transport failure. */
3003
+ readonly done: Promise<SubprocessOutcome>;
3004
+ /**
3005
+ * Write text to the terminal input.
3006
+ * @param data - text to deliver without implicit newline conversion.
3007
+ */
3008
+ write(data: string): Promise<void>;
3009
+ /**
3010
+ * Inspect the current foreground process group.
3011
+ * @returns its id and input-wait fact, or undefined when no foreground group can be resolved.
3012
+ */
3013
+ inspectForeground(): Promise<SubprocessTerminalForeground | undefined>;
3014
+ /**
3015
+ * Deliver a signal to the current foreground process group.
3016
+ * @param signal - permitted terminal signal.
3017
+ * @returns the exact group id that received it.
3018
+ */
3019
+ signalForeground(signal: SubprocessTerminalSignal): Promise<number>;
3020
+ /**
3021
+ * Idempotently terminate every terminal-session member the provider can still observe and await quiescence.
3022
+ * After settlement, no write, inspection, or signal call remains in flight.
3023
+ * Providers document substrate-specific observability limits.
3024
+ */
3025
+ terminate(): Promise<void>;
3026
+ }
3027
+ //#endregion
3028
+ //#region ../../node_modules/@deepseek-ai/dsh-subprocess/lib/types/index.d.ts
3029
+ declare module '@deepseek-ai/cordis' {
3030
+ interface Context {
3031
+ subprocess: SubprocessRuntime;
3032
+ }
3033
+ }
3034
+ /**
3035
+ * Abstract subprocess service. Subclass, implement {@link spawn}, and load the
3036
+ * subclass as a plugin — it registers as `ctx.subprocess` (one implementation
3037
+ * per context; loading a second throws, which is cordis' standard
3038
+ * duplicate-service behavior).
3039
+ *
3040
+ * Implementations must honor these semantics:
3041
+ * - Executable paths belong to one execution world shared with the mounted
3042
+ * filesystem provider.
3043
+ * - {@link spawn} returns immediately with a live handle; `done` resolves at
3044
+ * process close with exit facts and rejects only for spawn-level failures.
3045
+ * - Collect-mode readers are offset-based and non-consuming, so independent
3046
+ * readers never consume one another's output; lossy reads report truncation
3047
+ * and the spill file holding the complete stream when one exists. Piped
3048
+ * streams are handed to the caller raw and never buffered here.
3049
+ * - {@link SubprocessHandle.terminate} (and the spec's abort signal) escalates
3050
+ * SIGTERM→grace→SIGKILL — the only termination verb — tree-scoped on every
3051
+ * platform. {@link SubprocessHandle.waitForExit} observes whole-tree
3052
+ * liveness, so a consumer-owned teardown ladder can hold each tier on real
3053
+ * quiescence.
3054
+ * - Disposal of the service terminates all still-running managed processes
3055
+ * and awaits their exit.
3056
+ * - {@link spawnTerminal} owns terminal allocation, text transport,
3057
+ * foreground groups, signalling, and whole-session quiescence behind one
3058
+ * awaited termination method; readiness and persistent-shell policy stay
3059
+ * in the PTY consumer. Its output stream ends after queued terminal output
3060
+ * when the top-level process exits.
3061
+ */
3062
+ declare abstract class SubprocessRuntime extends Service {
3063
+ constructor(ctx: Context);
3064
+ /**
3065
+ * Resolve one configured executable in this provider's execution world.
3066
+ * Absolute paths are verified; bare names use the provider's scrubbed PATH
3067
+ * plus explicit environment overrides. Relative paths containing separators
3068
+ * are rejected: the resolution base is undefined, so providers fail loud
3069
+ * instead of guessing.
3070
+ * @param command - absolute executable path or bare PATH name.
3071
+ * @param env - explicit environment entries used for lookup.
3072
+ * @param signal - aborts remote or local lookup.
3073
+ * @returns a canonical executable path.
3074
+ */
3075
+ abstract resolveExecutable(command: string, env?: Readonly<Record<string, string>>, signal?: AbortSignal): Promise<string>;
3076
+ /**
3077
+ * Start one managed child process from a fully-specified spec; this seam
3078
+ * applies no defaults.
3079
+ * @param spec - argv, directory, stdio dispositions, grace, cancellation, and environment.
3080
+ * @returns the live process handle (streams/readers, signalling, outcome promise).
3081
+ */
3082
+ abstract spawn(spec: SubprocessSpawnSpec): SubprocessHandle;
3083
+ /**
3084
+ * Allocate a real terminal and start one owned process session. This is the
3085
+ * only non-pipe process primitive: implementations own terminal byte I/O,
3086
+ * foreground groups, signals, and complete session-tree cleanup.
3087
+ * @param spec - fully specified argv, cwd, environment, dimensions, grace, and allocation cancellation.
3088
+ * @returns the live terminal handle after allocation succeeds.
3089
+ */
3090
+ abstract spawnTerminal(spec: SubprocessTerminalSpawnSpec): Promise<SubprocessTerminalHandle>;
3091
+ }
3092
+ //#endregion
3093
+ //#region ../../node_modules/@deepseek-ai/dsh-shell/lib/types/types.d.ts
3094
+ /**
3095
+ * Sandbox facts for one run, present iff a sandboxing executor handled it.
3096
+ * Facts are reported independently of process exit status so callers can
3097
+ * distinguish command failures from policy denials and runner failures.
3098
+ */
3099
+ interface ShellSandboxInfo {
3100
+ /** The mode the command actually ran under. */
3101
+ mode: SandboxMode;
3102
+ /** Whether the sandbox denied a file operation. */
3103
+ denied: boolean;
3104
+ /** How completely the selected runner enforced the requested mode. */
3105
+ enforcement?: SandboxEnforcement;
3106
+ /** Whether the sandbox runner failed before the command could run. */
3107
+ runnerFailed?: boolean;
3108
+ }
3109
+ /**
3110
+ * A caller's execution REQUEST: `workdir` and `timeoutMs` are optional and
3111
+ * filled by {@link ShellExecutor.resolve} from the implementation's config.
3112
+ * This is the model-/plugin-facing shape; pass it to `resolve()` to obtain a
3113
+ * fully-resolved {@link ShellExecSpec}.
3114
+ */
3115
+ interface ShellExecRequest {
3116
+ command: string;
3117
+ /** Working directory override (default: implementation-configured). */
3118
+ workdir?: string | undefined;
3119
+ /** Timeout override in milliseconds (implementations cap it). */
3120
+ timeoutMs?: number | undefined;
3121
+ /**
3122
+ * Foreground stdout capture budget in bytes. Absent uses the executor's
3123
+ * default output cap. Trusted in-process consumers use this when they must
3124
+ * parse complete stdout up to their own bounded limit; the model-facing bash
3125
+ * tool does not expose it as a parameter.
3126
+ */
3127
+ stdoutMaxBytes?: number | undefined;
3128
+ /** Abort signal — implementations kill the command when it fires. */
3129
+ signal?: AbortSignal | undefined;
3130
+ /**
3131
+ * Bytes to write to the command's stdin, then close it. Absent leaves stdin
3132
+ * closed/empty (the default for model-driven tool calls). Set by in-process
3133
+ * plugins (e.g. the hooks bridges, which write a hook command's JSON payload
3134
+ * to its stdin); the model-facing bash tool does not expose it as a parameter
3135
+ * (a model that needs stdin uses shell syntax like a heredoc or a pipe).
3136
+ */
3137
+ stdin?: string | undefined;
3138
+ /**
3139
+ * Ordinary environment entries for the command, merged after the credential
3140
+ * scrub. Managed facts belong in {@link dshEnv}, which merges after this
3141
+ * map, so an entry here can never displace one. Set by in-process plugins
3142
+ * (the hooks bridges set `CLAUDE_PROJECT_DIR`, `CLAUDE_PLUGIN_ROOT`, …); the
3143
+ * model-facing bash tool does not expose it as a parameter.
3144
+ */
3145
+ env?: Record<string, string> | undefined;
3146
+ /**
3147
+ * Harness-owned `DSH_*` variables for this execution (typed to managed
3148
+ * keys). Executors discard ambient `DSH_*` entries before merging this
3149
+ * snapshot last, so an unavailable current fact cannot inherit a stale
3150
+ * value from the harness process and a caller {@link env} entry cannot
3151
+ * displace a managed one.
3152
+ */
3153
+ dshEnv?: DshEnvironment | undefined;
3154
+ /** Fully resolved per-call sandbox policy; sandboxing executors default it. */
3155
+ sandboxPolicy?: SandboxExecutionPolicy | undefined;
3156
+ }
3157
+ /**
3158
+ * A resolved execution spec. {@link ShellExecutor.resolve} fills and caps the
3159
+ * required fields; {@link ShellExecutor.start} ignores `timeoutMs` because
3160
+ * background processes have no executor timeout.
3161
+ */
3162
+ interface ShellExecSpec {
3163
+ command: string;
3164
+ workdir: string;
3165
+ timeoutMs: number;
3166
+ /**
3167
+ * Resolved foreground stdout capture budget in bytes. `run()` uses it for
3168
+ * stdout; background jobs and stderr keep the executor's own output cap.
3169
+ */
3170
+ stdoutMaxBytes: number;
3171
+ /** Abort signal — implementations kill the command when it fires. */
3172
+ signal?: AbortSignal | undefined;
3173
+ /** Bytes to write to stdin before closing it; absent means no stdin. */
3174
+ stdin?: string | undefined;
3175
+ /**
3176
+ * Ordinary environment entries carried through from
3177
+ * {@link ShellExecRequest.env}; {@link dshEnv} still merges after them.
3178
+ * OPTIONAL on the spec for the same reason as `stdin`: absent means no
3179
+ * ordinary extra environment.
3180
+ */
3181
+ env?: Record<string, string> | undefined;
3182
+ /** Managed `DSH_*` snapshot (typed to managed keys); merges after {@link env}. */
3183
+ dshEnv?: DshEnvironment | undefined;
3184
+ /** Resolved sandbox policy; ignored by executors that do not confine. */
3185
+ sandboxPolicy: SandboxExecutionPolicy | undefined;
3186
+ }
3187
+ /** The outcome of one completed (or killed) foreground run. */
3188
+ interface ShellRunResult {
3189
+ /** Exit code; null when the process died from a signal. */
3190
+ exitCode: number | null;
3191
+ /** Terminating signal (e.g. 'SIGTERM'); null on normal exit. */
3192
+ signal: NodeJS.Signals | null;
3193
+ /**
3194
+ * True when the executor's own timeout was the FIRST cause to cut the command
3195
+ * short. Mutually exclusive with {@link aborted}: one fused deadline drives
3196
+ * both the timeout and the caller's cancellation, so a timeout and an abort
3197
+ * racing before process close report the single first-abort cause, not both
3198
+ * (see the [timeout-library Agent Note](../../../../.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.md)).
3199
+ */
3200
+ timedOut: boolean;
3201
+ /**
3202
+ * True when the caller's `AbortSignal` was the FIRST cause to kill the command
3203
+ * (and it was not the executor's own timeout). Mutually exclusive with
3204
+ * {@link timedOut} — see there for the first-cause classification.
3205
+ */
3206
+ aborted: boolean;
3207
+ /** The effective timeout applied to this run (after defaulting/capping). */
3208
+ timeoutMs: number;
3209
+ stdout: CollectedOutput;
3210
+ stderr: CollectedOutput;
3211
+ /** Sandbox execution facts, absent for an unsandboxed executor. */
3212
+ sandbox?: ShellSandboxInfo;
3213
+ }
3214
+ /** Lifecycle of a background process. */
3215
+ type ShellProcessStatus = 'running' | 'completed' | 'killed';
3216
+ /** One incremental {@link ShellProcess.readOutput} read. */
3217
+ interface ShellProcessRead {
3218
+ /** Output produced since the previous read (stderr in a marked section). */
3219
+ delta: string;
3220
+ /** True when truncation dropped unread bytes the delta cannot include. */
3221
+ lossy: boolean;
3222
+ /** Full stdout spill file, when stdout truncation occurred and a safe path is available. */
3223
+ stdoutSpillPath?: string;
3224
+ /** Full stderr spill file, when stderr truncation occurred and a safe path is available. */
3225
+ stderrSpillPath?: string;
3226
+ }
3227
+ /**
3228
+ * A background process handle returned by {@link ShellExecutor.start}. It is the
3229
+ * only access path; buffered output remains readable after exit. Composition
3230
+ * teardown (the subprocess service's disposal) kills running processes and
3231
+ * awaits {@link done}; an executor-only reload leaves them running.
3232
+ */
3233
+ interface ShellProcess {
3234
+ /** Process lifecycle state (settled exactly once). */
3235
+ status: ShellProcessStatus;
3236
+ /** Exit code once finished (null = killed by signal / still running). */
3237
+ exitCode: number | null;
3238
+ /** Terminating signal name, when signal-killed. */
3239
+ signal: NodeJS.Signals | null;
3240
+ /** Resolves when the underlying process closes (never rejects — a spawn failure settles as `killed` with the error on stderr). */
3241
+ readonly done: Promise<void>;
3242
+ /** Sandbox facts, stamped once a confined process settles. */
3243
+ sandbox?: ShellSandboxInfo;
3244
+ /**
3245
+ * Read output produced since the previous read (consuming — consecutive
3246
+ * reads never re-deliver). Reads that lost data flag `lossy` and point at
3247
+ * full-stream spill files when available.
3248
+ */
3249
+ readOutput(): ShellProcessRead;
3250
+ /**
3251
+ * Kill the process group. Returns false when it had already finished
3252
+ * (no-op); idempotent.
3253
+ */
3254
+ kill(): boolean;
3255
+ }
3256
+ //#endregion
3257
+ //#region ../../node_modules/@deepseek-ai/dsh-shell/lib/types/index.d.ts
3258
+ declare module '@deepseek-ai/cordis' {
3259
+ interface Context {
3260
+ shell: ShellExecutor;
3261
+ }
3262
+ }
3263
+ /**
3264
+ * Abstract bash execution service. Subclass, implement the abstract methods,
3265
+ * and load the subclass as a plugin — it registers as `ctx.shell` (one
3266
+ * implementation per context; loading a second throws, which is cordis'
3267
+ * standard duplicate-service behavior).
3268
+ *
3269
+ * Implementations must honor these semantics:
3270
+ * - {@link run} rejects only for infrastructure failures. Nonzero exits,
3271
+ * timeout kills, and abort kills resolve with a {@link ShellRunResult}.
3272
+ * - {@link start} returns immediately; no timeout applies to background
3273
+ * processes. `done` settles at process close and never rejects; spawn
3274
+ * failures settle as `killed` with the error on stderr.
3275
+ * - {@link ShellProcess.readOutput} is incremental: consecutive reads never
3276
+ * repeat output. Lossy reads report truncation and available spill files.
3277
+ * - A still-running background process is stopped and awaited when its
3278
+ * owning composition tears down. With the subprocess seam that
3279
+ * boundary is `ctx.subprocess` disposal, so a background process survives
3280
+ * an executor-only reload.
3281
+ */
3282
+ declare abstract class ShellExecutor extends Service {
3283
+ constructor(ctx: Context);
3284
+ /**
3285
+ * The sandbox mode this executor applies by default, or `undefined` when it
3286
+ * does not sandbox commands.
3287
+ * @returns the configured default sandbox mode, when supported.
3288
+ */
3289
+ get sandboxMode(): SandboxMode | undefined;
3290
+ /**
3291
+ * Apply implementation-owned defaults and caps to a request before execution.
3292
+ * @param request - the caller's request; omitted fields get this
3293
+ * implementation's defaults, capped fields are clamped.
3294
+ * @returns the fully-specified spec to hand to {@link run}/{@link start}.
3295
+ */
3296
+ abstract resolve(request: ShellExecRequest): ShellExecSpec;
3297
+ /**
3298
+ * Run a command in the foreground; resolves when it finishes.
3299
+ * @param spec - a resolved spec from {@link resolve}, never a raw request.
3300
+ * @returns the outcome; nonzero exits, timeout kills, and abort kills
3301
+ * resolve with a descriptive result rather than reject.
3302
+ */
3303
+ abstract run(spec: ShellExecSpec): Promise<ShellRunResult>;
3304
+ /**
3305
+ * Start a background process and return its handle immediately.
3306
+ * @param spec - a resolved spec from {@link resolve}, never a raw request.
3307
+ * @returns the live process handle (reads, kill, quiescence promise).
3308
+ */
3309
+ abstract start(spec: ShellExecSpec): ShellProcess;
3310
+ }
3311
+ //#endregion
3312
+ //#region src/process-provider.d.ts
3313
+ declare class SshShellExecutor {
3314
+ private readonly executor;
3315
+ constructor(executor: SshExecutor);
3316
+ resolve(request: ShellExecRequest): ShellExecSpec;
3317
+ run(spec: ShellExecSpec): Promise<ShellRunResult>;
3318
+ start(spec: ShellExecSpec): ShellProcess;
3319
+ }
3320
+ declare class SshSubprocessRuntime {
3321
+ private readonly executor;
3322
+ constructor(executor: SshExecutor);
3323
+ spawn(spec: SubprocessSpawnSpec): SubprocessHandle;
3324
+ spawnTerminal(spec: SubprocessTerminalSpawnSpec): Promise<SubprocessTerminalHandle>;
3325
+ }
3326
+ //#endregion
3327
+ export { SshSubprocessRuntime as n, SshShellExecutor as t };
3328
+ //# sourceMappingURL=process-provider-CUgC5gyu.d.ts.map