@artenx/dshb 0.1.18 → 0.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/lib/auth/decorate-webserver.d.ts +2 -1
  2. package/lib/auth/decorate-webserver.js +21 -10
  3. package/lib/auth/decorate-webserver.js.map +1 -1
  4. package/lib/auth/gate.d.ts +3 -1
  5. package/lib/auth/gate.js +18 -1
  6. package/lib/auth/gate.js.map +1 -1
  7. package/lib/auth/index.js +11 -3
  8. package/lib/auth/index.js.map +1 -1
  9. package/lib/auth/webserver.d.ts +3 -1
  10. package/lib/auth/webserver.js +10 -1
  11. package/lib/auth/webserver.js.map +1 -1
  12. package/lib/client.js +2157 -567
  13. package/lib/client.js.map +1 -1
  14. package/lib/core/index.js +72 -4
  15. package/lib/core/index.js.map +1 -1
  16. package/lib/core/node-registry.d.ts +2 -108
  17. package/lib/core/node-registry.js +43 -2
  18. package/lib/core/node-registry.js.map +1 -1
  19. package/lib/core/routes.d.ts +4 -3
  20. package/lib/core/routes.js +67 -23
  21. package/lib/core/routes.js.map +1 -1
  22. package/lib/core/sync/coordinator.d.ts +48 -0
  23. package/lib/core/sync/coordinator.js +247 -0
  24. package/lib/core/sync/coordinator.js.map +1 -0
  25. package/lib/core/sync/host-key.d.ts +2 -0
  26. package/lib/core/sync/host-key.js +71 -0
  27. package/lib/core/sync/host-key.js.map +1 -0
  28. package/lib/core/sync/internal-routes.d.ts +9 -0
  29. package/lib/core/sync/internal-routes.js +236 -0
  30. package/lib/core/sync/internal-routes.js.map +1 -0
  31. package/lib/core/sync/model.d.ts +2 -0
  32. package/lib/core/sync/model.js +106 -0
  33. package/lib/core/sync/model.js.map +1 -0
  34. package/lib/core/sync/node-sync.d.ts +2 -0
  35. package/lib/core/sync/node-sync.js +660 -0
  36. package/lib/core/sync/node-sync.js.map +1 -0
  37. package/lib/core/sync/offline-archive.d.ts +55 -0
  38. package/lib/core/sync/offline-archive.js +673 -0
  39. package/lib/core/sync/offline-archive.js.map +1 -0
  40. package/lib/core/sync/offline-journal.d.ts +22 -0
  41. package/lib/core/sync/offline-journal.js +74 -0
  42. package/lib/core/sync/offline-journal.js.map +1 -0
  43. package/lib/core/sync/offline-routes.d.ts +7 -0
  44. package/lib/core/sync/offline-routes.js +192 -0
  45. package/lib/core/sync/offline-routes.js.map +1 -0
  46. package/lib/core/sync/peer-manager.d.ts +56 -0
  47. package/lib/core/sync/peer-manager.js +258 -0
  48. package/lib/core/sync/peer-manager.js.map +1 -0
  49. package/lib/core/sync/protocol.d.ts +2 -0
  50. package/lib/core/sync/protocol.js +124 -0
  51. package/lib/core/sync/protocol.js.map +1 -0
  52. package/lib/core/sync/remote-helper.d.ts +5 -0
  53. package/lib/core/sync/remote-helper.js +160 -0
  54. package/lib/core/sync/remote-helper.js.map +1 -0
  55. package/lib/core/sync/revision.d.ts +2 -0
  56. package/lib/core/sync/revision.js +77 -0
  57. package/lib/core/sync/revision.js.map +1 -0
  58. package/lib/core/sync/routes.d.ts +9 -0
  59. package/lib/core/sync/routes.js +339 -0
  60. package/lib/core/sync/routes.js.map +1 -0
  61. package/lib/core/sync/scheduler.d.ts +14 -0
  62. package/lib/core/sync/scheduler.js +81 -0
  63. package/lib/core/sync/scheduler.js.map +1 -0
  64. package/lib/core/sync/session-journal.d.ts +2 -0
  65. package/lib/core/sync/session-journal.js +191 -0
  66. package/lib/core/sync/session-journal.js.map +1 -0
  67. package/lib/core/sync/session-routes.d.ts +7 -0
  68. package/lib/core/sync/session-routes.js +67 -0
  69. package/lib/core/sync/session-routes.js.map +1 -0
  70. package/lib/core/sync/session-sync.d.ts +2 -0
  71. package/lib/core/sync/session-sync.js +2 -0
  72. package/lib/core/sync/ssh-transport.d.ts +2 -0
  73. package/lib/core/sync/ssh-transport.js +408 -0
  74. package/lib/core/sync/ssh-transport.js.map +1 -0
  75. package/lib/core/sync/stores.d.ts +3 -0
  76. package/lib/core/sync/stores.js +385 -0
  77. package/lib/core/sync/stores.js.map +1 -0
  78. package/lib/core/test.d.ts +1 -1
  79. package/lib/core/workspace-bindings.d.ts +2 -28
  80. package/lib/core/workspace-bindings.js +14 -14
  81. package/lib/core/workspace-bindings.js.map +1 -1
  82. package/lib/core/workspace-instruction-context.d.ts +3 -2260
  83. package/lib/core/workspace-instruction-context.js +104 -2
  84. package/lib/core/workspace-instruction-context.js.map +1 -0
  85. package/lib/core/workspace-instruction-routes.d.ts +1 -1
  86. package/lib/core/workspace-instructions.d.ts +2 -68
  87. package/lib/core/workspace-instructions.js +13 -0
  88. package/lib/core/workspace-instructions.js.map +1 -1
  89. package/lib/core/workspaces.d.ts +4 -3
  90. package/lib/core/workspaces.js +17 -1
  91. package/lib/core/workspaces.js.map +1 -1
  92. package/lib/host-key-C5afhAUd.d.ts +30 -0
  93. package/lib/index-VF8bcBeX.d.ts +2293 -0
  94. package/lib/{workspace-instruction-context-DytAmaPY.js → lib-gdtU_WKT.js} +159 -102
  95. package/lib/lib-gdtU_WKT.js.map +1 -0
  96. package/lib/model-BP7Gw1yk.d.ts +104 -0
  97. package/lib/node-registry-BTnnM5-k.d.ts +112 -0
  98. package/lib/node-sync-3Z9QLz2n.d.ts +89 -0
  99. package/lib/protocol-CV7LGE44.d.ts +35 -0
  100. package/lib/revision-C9sOlDZ6.d.ts +25 -0
  101. package/lib/router/router-fs.d.ts +12 -3
  102. package/lib/router/router-fs.js.map +1 -1
  103. package/lib/session-journal-pgPqcWn9.d.ts +40 -0
  104. package/lib/session-sync-EdfwUON5.js +2177 -0
  105. package/lib/session-sync-EdfwUON5.js.map +1 -0
  106. package/lib/session-sync-g6qKZzjV.d.ts +1252 -0
  107. package/lib/ssh-transport-BcIiLxsX.d.ts +55 -0
  108. package/lib/stores-CKyEt0yk.d.ts +31 -0
  109. package/lib/workspace-bindings-CsB0TIJB.d.ts +28 -0
  110. package/lib/workspace-instructions-DirYYiku.d.ts +69 -0
  111. package/package.json +20 -1
  112. package/lib/workspace-instruction-context-DytAmaPY.js.map +0 -1
@@ -0,0 +1,1252 @@
1
+ import { o as NodeRegistry } from "./node-registry-BTnnM5-k.js";
2
+ import { r as WorkspaceBindingsStore } from "./workspace-bindings-CsB0TIJB.js";
3
+ import { r as SyncRevision } from "./revision-C9sOlDZ6.js";
4
+ import { d as SyncSessionArchive, i as SyncOrigin, l as SyncRecordMetadata, r as SyncImportMethod } from "./model-BP7Gw1yk.js";
5
+ import { n as SyncStateStore } from "./stores-CKyEt0yk.js";
6
+ import { s as SyncNodeService } from "./node-sync-3Z9QLz2n.js";
7
+ import { S as BrandedNumber, _ as FileAttachmentRef, a as SystemPromptUpdate, b as TypertResource, c as ToolSchema, d as Message, f as SystemMessage, g as ToolCallId, i as LlmFailure, l as AssistantMessage, m as UserMessage, n as LlmCallConfig, o as TokenUsage, p as ToolResultMessage, r as LlmCallConfigAdapterDefaults, s as ToolHistory, t as AssistantStreamRecord, u as DeveloperMessage, v as ImageAttachmentRef, x as Branded, y as TypertLookup } from "./index-VF8bcBeX.js";
8
+ import { a as SessionInstructionSnapshotStore } from "./workspace-instructions-DirYYiku.js";
9
+ import { t as SyncSessionJournalStore } from "./session-journal-pgPqcWn9.js";
10
+ import { Context, Service } from "@deepseek-ai/cordis";
11
+ //#region ../../node_modules/@deepseek-ai/dsh-scope/lib/types/index.d.ts
12
+ declare const ScopedBrand: unique symbol;
13
+ /**
14
+ * A routing-only event receiver built by {@link scopeTarget}. The type
15
+ * parameter records the subject type for dispatch checking; the carrier does
16
+ * not expose the subject's properties. Event payloads carry the real subject.
17
+ */
18
+ type Scoped<T extends object> = object & {
19
+ readonly [ScopedBrand]: T;
20
+ };
21
+ //#endregion
22
+ //#region ../../node_modules/@deepseek-ai/dsh-util-values/lib/types/index.d.ts
23
+ /** Duplicate-install-safe JSON and immutable-value helpers. @module @deepseek-ai/dsh-util-values */
24
+ /** A value that round-trips through JSON without loss. */
25
+ type JsonValue = null | boolean | number | string | JsonValue[] | {
26
+ [key: string]: JsonValue;
27
+ };
28
+ //#endregion
29
+ //#region ../../node_modules/@deepseek-ai/dsh-session/lib/types/types.d.ts
30
+ /** Identifies one session in the store (and its persistence artifacts). */
31
+ type SessionId = Branded<'SessionId'>;
32
+ /**
33
+ * Brand a string as a {@link SessionId}.
34
+ * @param id - the raw session id string.
35
+ * @returns the same string with the session-id brand.
36
+ */
37
+ declare function SessionId(id: string): SessionId;
38
+ /** Sequence number of one existing event in a Session log. */
39
+ type SessionSeq = BrandedNumber<'SessionSeq'>;
40
+ /**
41
+ * Admit a numeric value as an existing Session event position.
42
+ * @param value - non-negative safe integer admitted by the owning log operation.
43
+ * @returns the same number with the Session-sequence brand.
44
+ */
45
+ declare function SessionSeq(value: number): SessionSeq;
46
+ /** A Session log gap, prefix length, or read offset, which may equal the event count. */
47
+ type SessionLogOffset = BrandedNumber<'SessionLogOffset'>;
48
+ /**
49
+ * Admit a numeric value as a Session log offset.
50
+ * @param value - non-negative safe integer used as a gap or prefix length.
51
+ * @returns the same number with the Session-log-offset brand.
52
+ */
53
+ declare function SessionLogOffset(value: number): SessionLogOffset;
54
+ /**
55
+ * Current logical Session format version, stamped into every newly written
56
+ * {@link SessionHeader}. Current Session and persistence code accept only this
57
+ * value; header-only readers classify supported historical formats, while an
58
+ * event-body read composes the build-static adjacent chain and publishes only
59
+ * this final generation before constructing a Session.
60
+ *
61
+ * The version is a single monotonic integer with no major/minor split. Retain
62
+ * it when older readers resume correctly, preserve safely ignorable records,
63
+ * or refuse required features before execution, mutation, or tail repair.
64
+ * New readers must preserve historical meanings, including logs mixing old
65
+ * and new record representations. Bump when an existing discriminator cannot
66
+ * prevent unsafe interpretation; a structural difference alone is insufficient.
67
+ * Unknown fields and values require evidence of the released reader's actual
68
+ * admission behavior. The per-event {@link SessionEvent.ignorable} marker
69
+ * governs unknown event types, not arbitrary nested payload changes.
70
+ * Same-version readers retain earlier representations: the adjacent migration
71
+ * chain does not run when stored and current versions match. A subsequent
72
+ * migration must account for all supported representations of its source.
73
+ * Compatibility review and the retained migration obligations are recorded in
74
+ * `.agents/notes/implemented/process/2026-10-08-session-reader-compatibility-review.md`.
75
+ */
76
+ declare const SESSION_FORMAT_VERSION = 4;
77
+ /**
78
+ * Immutable validated storage metadata, kept outside the conversation event log.
79
+ */
80
+ interface SessionHeader {
81
+ /**
82
+ * Current logical format version, stamped from {@link SESSION_FORMAT_VERSION}.
83
+ * Historical physical headers are translated before entering this interface.
84
+ */
85
+ readonly version: typeof SESSION_FORMAT_VERSION;
86
+ /** The session's id (mirrors the {@link Session}'s id). */
87
+ readonly id: SessionId;
88
+ /** Non-negative safe-integer Unix epoch milliseconds when the session was created. */
89
+ readonly createdAt: number;
90
+ /** Absolute working directory the session was created in (if any). */
91
+ readonly cwd?: string;
92
+ /** The session this one was forked from (seed lineage), if any. */
93
+ readonly parentSession?: SessionId;
94
+ /**
95
+ * Whether this Session contains a fork-inherited event prefix. The exact prefix
96
+ * length is Session state rather than ordinary header metadata.
97
+ */
98
+ readonly isSeeded: boolean;
99
+ /**
100
+ * Coarse product classification for a session created as a subagent child.
101
+ * This is presentation metadata, not proof that the child is continuable.
102
+ */
103
+ readonly origin?: 'subagent';
104
+ /**
105
+ * Delegation depth: absent (zero) for a top-level session, parent depth + 1
106
+ * for a subagent child. Persisted so a recursion budget survives restart and
107
+ * resume — a runtime-only depth would reset a resumed child to top-level.
108
+ */
109
+ readonly delegationDepth?: number;
110
+ /**
111
+ * Id of the agent preset this session's agent was composed from, when the
112
+ * deployment composes per session. Durable because the preset decides the
113
+ * session's tools and prompt: a resume that restored a different composition
114
+ * would replay history the model can no longer act on.
115
+ */
116
+ readonly agentPreset?: string;
117
+ }
118
+ /**
119
+ * Options for creating a {@link Session} via the store. `seed` replays/forks
120
+ * an existing event log; `meta` carries the caller-supplied storage fields the
121
+ * store folds into a {@link SessionHeader}.
122
+ */
123
+ interface CreateSessionOptions {
124
+ /** Initial replay or fork history supplied at construction. */
125
+ readonly seed?: readonly SessionEvent[];
126
+ /**
127
+ * Exact fork-inherited prefix length when `meta.isSeeded` is true. The
128
+ * constructor appends the child-owned tagged marker at the cut unless
129
+ * the seed already includes it followed by child-owned fork closers.
130
+ */
131
+ readonly inheritedEventCount?: SessionLogOffset;
132
+ /**
133
+ * Storage metadata read once before publication. `isSeeded` marks fork
134
+ * lineage; supplying replay history alone does not make it inherited.
135
+ */
136
+ readonly meta?: {
137
+ readonly cwd?: string;
138
+ readonly parentSession?: SessionId;
139
+ readonly createdAt?: number;
140
+ readonly isSeeded?: boolean;
141
+ readonly origin?: 'subagent';
142
+ readonly delegationDepth?: number;
143
+ readonly agentPreset?: string;
144
+ };
145
+ }
146
+ /**
147
+ * Aliasing state of an adoptable Session seed. `shared-frozen` permits deeply
148
+ * frozen aliases plus independently owned unfrozen values in the same seed.
149
+ */
150
+ type SessionSeedEventState = 'detached' | 'shared-frozen';
151
+ /**
152
+ * Adoptable storage values transferred to {@link SessionStore.prepare}
153
+ * without another copy or freeze pass.
154
+ */
155
+ interface RestoredSessionOptions {
156
+ /** Events that are independently owned or already deeply frozen. */
157
+ readonly seed: SessionEvent[];
158
+ /** Independently owned storage metadata to validate and freeze in place. */
159
+ readonly meta: SessionHeader;
160
+ /** Exact number of fork-inherited leading events decoded from storage. */
161
+ readonly inheritedEventCount: SessionLogOffset;
162
+ /** Aliasing state carried from the operation that produced the seed. */
163
+ readonly eventState: SessionSeedEventState;
164
+ }
165
+ /** Inputs accepted while constructing an unpublished Session. */
166
+ type PrepareSessionOptions = (CreateSessionOptions & {
167
+ readonly eventState?: undefined;
168
+ }) | RestoredSessionOptions;
169
+ /** Why an active agent driver was cancelled. */
170
+ type AgentCancelCause = {
171
+ readonly kind: 'user';
172
+ } | {
173
+ readonly kind: 'parent';
174
+ } | {
175
+ readonly kind: 'hook';
176
+ readonly reason: string;
177
+ } | {
178
+ readonly kind: 'disposed';
179
+ };
180
+ /** Durable cancellation cause, including imports whose original coarse record carried no cause. */
181
+ type TurnEndCancelCause = AgentCancelCause | {
182
+ readonly kind: 'legacy';
183
+ };
184
+ /**
185
+ * Why a turn ended. Merge-extensible sum type.
186
+ */
187
+ interface TurnEndReasonMap {
188
+ completed: {
189
+ kind: 'completed';
190
+ };
191
+ /** A cancellation request interrupted the live turn. */
192
+ aborted: {
193
+ kind: 'aborted';
194
+ reason: TurnEndCancelCause;
195
+ };
196
+ blocked: {
197
+ kind: 'blocked';
198
+ };
199
+ /**
200
+ * The turn failed. `error` is always a structured failure: the `LlmError`
201
+ * facts verbatim, or `{ message: errorChain(error), code: 'UNKNOWN' }`
202
+ * flattened from any other error.
203
+ */
204
+ error: {
205
+ kind: 'error';
206
+ error: LlmFailure;
207
+ };
208
+ /** At least one step reached its output-token ceiling, even if a plugin continued the turn. */
209
+ 'max-tokens': {
210
+ kind: 'max-tokens';
211
+ };
212
+ /**
213
+ * A crash-orphaned turn was closed after the fact: agent-loop resume appends
214
+ * this closer for a stored log whose last turn never ended, and session-query
215
+ * synthesizes it on cold reads. The loop never emits this marker live, and
216
+ * the events recorded before the crash remain intact.
217
+ */
218
+ interrupted: {
219
+ kind: 'interrupted';
220
+ };
221
+ /**
222
+ * Fork-seed construction closed a turn that was still open at the fork
223
+ * boundary in the source session. Only fork seeds carry this marker — the
224
+ * loop never emits it — and the source events before the boundary remain
225
+ * intact in the child.
226
+ */
227
+ forked: {
228
+ kind: 'forked';
229
+ };
230
+ }
231
+ /** The union over {@link TurnEndReasonMap} — why a turn ended; plugins extend it by merging variants into the map. */
232
+ type TurnEndReason = TurnEndReasonMap[keyof TurnEndReasonMap];
233
+ /**
234
+ * Logged request state outside derived history: call config and tools. The
235
+ * system prompt is derived history — surface node 0, a `system/message` event.
236
+ * The latest full `request/header` snapshot reconstructs the header; canonical
237
+ * empty optional fields are absent.
238
+ */
239
+ interface EpochHeader {
240
+ /** The conversation's call configuration (provider, model, reasoning effort, and sampling scalars). */
241
+ config: LlmCallConfig;
242
+ /** Effective config fields materialized from the exact adapter rather than proposed by a caller. */
243
+ adapterDefaults?: LlmCallConfigAdapterDefaults;
244
+ /** Assembled tool schemas; absent for a tool-less request. */
245
+ tools?: ToolSchema[];
246
+ /** Retired request text; system prompts belong to system/message events.
247
+ * @persistenceReserved
248
+ */
249
+ system?: never;
250
+ }
251
+ /** Registration-bound metadata for one resolved model route. */
252
+ interface RequestContext {
253
+ /** Registered provider route the metadata belongs to. */
254
+ provider: string;
255
+ /** Provider-owned model id the metadata belongs to. */
256
+ model: string;
257
+ /** Maximum combined request and response context in tokens, when advertised. */
258
+ contextWindow?: number;
259
+ /** `'in-history'` when the route reads the latest `system` message at any position as the effective system prompt. */
260
+ systemPromptUpdate?: SystemPromptUpdate;
261
+ }
262
+ /**
263
+ * Why a `request/header` snapshot was appended: `'initial'` — the log's first
264
+ * header (a new conversation); `'resume'` — a loop instance's first request
265
+ * over a log that already has header events (process restart, fork seed);
266
+ * `'change'` — a later request used a different header; `'series'` — an unchanged
267
+ * header began an explicitly distinct message series or followed a surface
268
+ * replacement. Other reasons carry `startsSeries` when a new series coincides.
269
+ */
270
+ type RequestHeaderReason = 'initial' | 'resume' | 'change' | 'series';
271
+ /**
272
+ * The merge-extensible, append-only source of truth for an agent interaction.
273
+ * Message history is derived from this log. Every event is lossless JSON and
274
+ * sequence numbers stay contiguous. Assistant attempt events embed their exact
275
+ * compact raw streams so persistence stores one durable settlement per attempt.
276
+ */
277
+ interface SessionEventMap {
278
+ /**
279
+ * Opens turn `turn` before the loop claims queued input or runs pre-step.
280
+ * Rejection, empty input, cancellation, or failure may close it with no
281
+ * step; otherwise the following identified `user/message` event or batch
282
+ * records the messages entering the step.
283
+ */
284
+ 'turn/start': {
285
+ turn: number;
286
+ };
287
+ /**
288
+ * Closes turn `turn` with the {@link TurnEndReason} that ended it. A turn
289
+ * with no entered step has no `step/start` or `step/end`. The loop does not await a
290
+ * flush at turn boundaries: `dsh-session-checkpoint-policy` owns the
291
+ * per-request durability checkpoint, and consumers that read storage after
292
+ * `whenIdle()` flush themselves. Success commits the turn; rejection is
293
+ * reported live and does not prevent later work.
294
+ */
295
+ 'turn/end': {
296
+ turn: number;
297
+ reason: TurnEndReason;
298
+ };
299
+ /** Opens step `step` of turn `turn` — one model call plus the tool executions it requested. */
300
+ 'step/start': {
301
+ turn: number;
302
+ step: number;
303
+ };
304
+ /** Closes step `step` of turn `turn`. */
305
+ 'step/end': {
306
+ turn: number;
307
+ step: number;
308
+ };
309
+ /**
310
+ * A user-role message on the model-visible surface: a direct human prompt
311
+ * (the queued message claimed for this turn), a synthetic `agent.inject()`
312
+ * context (file-change notices, subdir AGENTS.md, skill content, cron
313
+ * notifications, …), or an entered goal continuation round. All three
314
+ * project their `content` verbatim; `source` tells them apart.
315
+ */
316
+ 'user/message': UserMessage;
317
+ /** An incremental agent session change admitted at the named turn and step. */
318
+ 'developer/message': {
319
+ turn: number;
320
+ step: number;
321
+ message: DeveloperMessage;
322
+ /** Earlier request/header defining every tool addition; required exactly when additions are present. */
323
+ headerSeq?: SessionSeq;
324
+ };
325
+ /**
326
+ * The rendered system prompt on the model-visible surface. The loop appends
327
+ * the first one as surface node 0 before the step's first `user/message`.
328
+ * A prepared in-history route can append nonempty changes in a continuing
329
+ * series. An incapable route or new series normalizes text to the first system
330
+ * node. Normalization empties nonempty later nodes, then rewrites the head if
331
+ * needed, through logged per-node replacements. An empty rendering always
332
+ * clears all active system nodes, leaving no older instructions model-visible.
333
+ * Empty later nodes are dormant and project to no message; an empty head with
334
+ * no active later node records "no system prompt". Restored nonempty text follows
335
+ * the same route and series rule; empty nodes never restore older text.
336
+ */
337
+ 'system/message': {
338
+ turn: number;
339
+ step: number;
340
+ message: SystemMessage;
341
+ };
342
+ /**
343
+ * Assembled assistant message for one step (derived history uses this).
344
+ * Carries the step's `usage` when the adapter reported token accounting, so
345
+ * the model output and its accounting travel together (there is no separate
346
+ * usage record). `usage` is absent when the adapter reported none. A turn
347
+ * cancelled mid-stream finalizes its delivered text/reasoning prefix as this
348
+ * event with `interrupted: true`; undispatched tool calls are absent. The
349
+ * marker distinguishes that prefix without re-deriving interruption from turn
350
+ * boundaries. An aborted turn with no such event streamed no visible content.
351
+ */
352
+ 'assistant/message': {
353
+ turn: number;
354
+ step: number;
355
+ message: AssistantMessage;
356
+ /** Exact timed model stream, compacted without joining delta boundaries. */
357
+ stream: AssistantStreamRecord[];
358
+ usage?: TokenUsage;
359
+ interrupted?: true;
360
+ };
361
+ /**
362
+ * One model attempt that committed no surface message. The embedded stream
363
+ * preserves a failed, retried, cancelled, or stream-error attempt that
364
+ * reached settlement without fabricating model-visible history.
365
+ */
366
+ 'assistant/attempt': {
367
+ turn: number;
368
+ step: number;
369
+ stream: AssistantStreamRecord[];
370
+ };
371
+ /**
372
+ * The model requested one tool invocation: `name` with the raw `arguments`
373
+ * JSON string exactly as the model produced it (unparsed). `callId` pairs the
374
+ * call with its `tool/result`.
375
+ */
376
+ 'tool/call': {
377
+ turn: number;
378
+ step: number;
379
+ callId: ToolCallId;
380
+ name: string;
381
+ arguments: string;
382
+ };
383
+ /**
384
+ * A completed tool call's model-facing result, optional internal failure
385
+ * identity and user-facing reason, and optional tool-private `meta`
386
+ * presentation payload. The reason remains outside the model-facing message.
387
+ * `meta` is
388
+ * opaque to the core (the producing tool owns its shape and reads it back in
389
+ * `presentResult`) but MUST be JSON-serializable: `Session.append`
390
+ * runtime-validates all event data with `isJsonValue`, so a non-serializable
391
+ * `meta` is rejected at the source, and the durable log reproduces the
392
+ * identical card on replay. Absent
393
+ * unless the tool attaches one (e.g. `dsh-tool-fs` carries its result-time
394
+ * contextual diff here).
395
+ */
396
+ 'tool/result': {
397
+ turn: number;
398
+ step: number;
399
+ message: ToolResultMessage;
400
+ /**
401
+ * Optional failure identity and raw user-facing reason, outside model content;
402
+ * allowed only when the message has `isError: true`.
403
+ */
404
+ error?: {
405
+ name: string;
406
+ code: string;
407
+ reason?: string;
408
+ };
409
+ meta?: JsonValue;
410
+ };
411
+ /**
412
+ * Full header for the next request, appended inside its step before dispatch.
413
+ * It is log-only; the latest snapshot reconstructs the request header.
414
+ */
415
+ 'request/header': {
416
+ header: EpochHeader;
417
+ reason: RequestHeaderReason;
418
+ /** This request begins a distinct model-message series, independently of the header reason. */
419
+ startsSeries?: true;
420
+ };
421
+ /**
422
+ * Route metadata for the next request, logged only when the route, capacity,
423
+ * or system prompt update mode changes. It does not participate in request
424
+ * reconstruction or header equality. Prompt admission uses the bound prepared
425
+ * call's capability, not this snapshot from an earlier request.
426
+ */
427
+ 'request/context': RequestContext;
428
+ /**
429
+ * Separates inherited or restored history from later lifecycle-owned work.
430
+ * This log-only marker need not be at {@link Session.firstLiveSeq}: a fork
431
+ * seed can already contain its tagged marker and child-owned synthetic
432
+ * closers before construction.
433
+ *
434
+ * A fresh fork child owns one `{ inherited: true }` marker at its exact
435
+ * inherited-prefix cut, even when that prefix ends in an ancestor marker.
436
+ * `buildForkSeed` appends that marker before any synthetic closers; the
437
+ * `Session` constructor supplies it when given only the inherited prefix.
438
+ * The last tagged marker is the current Session's cut; untagged markers
439
+ * keep ordinary restore and replay lifecycle boundaries.
440
+ *
441
+ * Only the `Session` constructor and `buildForkSeed` may create this marker.
442
+ * Session append does not reject other writers, so a plugin appending one
443
+ * would silently classify every live bracket before it as seed history.
444
+ *
445
+ * An owner of a standalone open/close bracket (`compaction/start` …
446
+ * `compaction/end`) reads it because seed history and live work are otherwise
447
+ * byte-identical: an unmatched opening marker before this event belongs to
448
+ * an ended lifecycle, whatever ended it. NOT a liveness signal about other
449
+ * writers — a concurrently live session holds its own boundary elsewhere,
450
+ * so tolerating concurrent writers needs a signal beyond the log.
451
+ */
452
+ 'session/end-seed': {
453
+ inherited?: true;
454
+ };
455
+ }
456
+ /** The appendable event-type keys of {@link SessionEventMap}, plugin-merged extensions included. */
457
+ type SessionEventType = keyof SessionEventMap;
458
+ /**
459
+ * The subset of {@link SessionEventType} values whose events produce LLM
460
+ * messages and are eligible to appear on the ordered surface. Only these
461
+ * event types may carry {@link SurfaceOp}; system, user, and tool events may also cite
462
+ * earlier sources through {@link SessionEvent.sourceEventSeqs}.
463
+ */
464
+ type SurfaceEventType = 'system/message' | 'developer/message' | 'user/message' | 'assistant/message' | 'tool/result';
465
+ /**
466
+ * How a session event entered the ordered surface. Only valid on
467
+ * {@link SurfaceEventType} events.
468
+ *
469
+ * - `'append'`: added to the tail — normal path for user/assistant/tool
470
+ * messages.
471
+ * - `{ op: 'replace', startSeq, endSeq }`: replaces surface nodes from `startSeq`
472
+ * (inclusive) through `endSeq` (inclusive) with this node. Both must exist as
473
+ * surface nodes in the current surface. `startSeq === endSeq` replaces a single
474
+ * node. The node's {@link SessionEvent.sourceEventSeqs} must include every
475
+ * shadowed surface node. Used by compaction; any surface-replacing producer
476
+ * may use it.
477
+ */
478
+ type SurfaceOp = 'append' | {
479
+ op: 'replace';
480
+ startSeq: SessionSeq;
481
+ endSeq: SessionSeq;
482
+ };
483
+ /**
484
+ * Surface placement and cited source-event seqs for {@link Session.append}. Required on
485
+ * message-producing events and forbidden on log-only events.
486
+ */
487
+ type SurfaceIntent<T extends SurfaceEventType = SurfaceEventType> = {
488
+ surfaceOp: SurfaceOp;
489
+ } & (T extends 'assistant/message' ? {
490
+ /** Assistant messages embed their provider stream instead of citing source events. */
491
+ sourceEventSeqs?: never;
492
+ } : {
493
+ /** Complete non-empty set of known earlier source-event seqs. */
494
+ sourceEventSeqs?: SessionSeq[];
495
+ });
496
+ /**
497
+ * One immutable entry in the session log.
498
+ *
499
+ * A proper discriminated union over `type` (not independent `type`/`data`
500
+ * unions), so `switch (event.type)` narrows `event.data` without casts.
501
+ *
502
+ * The {@link sourceEventSeqs} and {@link surfaceOp} fields are conditional:
503
+ * they only exist on {@link SurfaceEventType} variants (`system/message`, `user/message`,
504
+ * `assistant/message`, `tool/result`).
505
+ * Non-surface events (boundary markers, attempts, errors) never carry
506
+ * surface metadata — the compiler enforces this at `Session.append()`
507
+ * call sites.
508
+ */
509
+ type SessionEvent<T extends SessionEventType = SessionEventType> = { [K in SessionEventType]: {
510
+ type: K;
511
+ /** Monotonic sequence number within the session. */
512
+ seq: SessionSeq;
513
+ /** Unix epoch milliseconds. */
514
+ time: number;
515
+ data: SessionEventMap[K];
516
+ /**
517
+ * Marks an event a reader may safely skip when it does not recognize
518
+ * `type`. Absent means required: a reader meeting an unrecognized type
519
+ * without this marker MUST refuse to reconstruct the session instead of
520
+ * silently dropping the event, because an unrecognized required event may
521
+ * change how the rest of the log is interpreted. A writer sets `true` only
522
+ * on purely informational records whose loss cannot affect reconstruction;
523
+ * defaulting to required means a forgotten marker over-refuses (an
524
+ * inconvenience) rather than silently resuming a gutted session.
525
+ */
526
+ ignorable?: true;
527
+ } & (K extends SurfaceEventType ? SurfaceIntent<K> : {
528
+ surfaceOp?: never;
529
+ sourceEventSeqs?: never;
530
+ }); }[T];
531
+ declare module '@deepseek-ai/dsh-typert-protocol' {
532
+ interface TypertResourceMap {
533
+ /** One Session; the Session Controller registers its default `sessionId` wire field. */
534
+ session: TypertResource<SessionId>;
535
+ }
536
+ interface RemoteErrorDetailsMap {
537
+ /** The named Session does not exist; produced by every layer that resolves a SessionId. */
538
+ 'session/not-found': {
539
+ readonly sessionId: SessionId;
540
+ };
541
+ }
542
+ }
543
+ //#endregion
544
+ //#region ../../node_modules/@deepseek-ai/dsh-session/lib/types/surface.d.ts
545
+ /** Readonly history immediately before a message-projection event. */
546
+ interface SessionMessageProjectionContext {
547
+ /** Current message-producing event sequences in model-visible order. */
548
+ nodes: readonly SessionSeq[];
549
+ /** Contiguous event window; entries at or beyond the candidate seq are not committed inputs. */
550
+ events: readonly SessionEvent[];
551
+ /** Absolute sequence of the window's first event. */
552
+ baseSeq: SessionLogOffset;
553
+ /** Previously projected messages keyed by their original event sequences. */
554
+ messages: ReadonlyMap<SessionSeq, Message>;
555
+ }
556
+ /** Pure interpretation of one plugin-owned event that changes existing message content. */
557
+ interface SessionMessageProjection<T extends SessionEventType = SessionEventType> {
558
+ /** Event interpreted by this definition; declare it with `@messageProjection` in SessionEventMap. */
559
+ type: T;
560
+ /**
561
+ * Validate the complete durable decision before returning any updates. Preserve
562
+ * message identities and publish immutable copies without mutating the input.
563
+ * @param event - candidate event, not yet applied to the supplied history.
564
+ * @param context - history preceding this decision.
565
+ * @returns changed current messages keyed by their original sequences.
566
+ * @throws when the durable decision cannot be applied to this history.
567
+ */
568
+ project(event: SessionEvent<T>, context: SessionMessageProjectionContext): ReadonlyMap<SessionSeq, Message>;
569
+ }
570
+ /** Readonly live projection of the message-producing session events. */
571
+ interface SessionSurface {
572
+ /** Current surface event sequences in model-visible order. */
573
+ readonly nodes: readonly SessionSeq[];
574
+ /** Monotonic count of committed positional replacements. */
575
+ readonly replaceGeneration: number;
576
+ /** Monotonic count of committed replacements and plugin-owned message changes. */
577
+ readonly contentGeneration: number;
578
+ }
579
+ //#endregion
580
+ //#region ../../node_modules/@deepseek-ai/dsh-session/lib/types/index.d.ts
581
+ declare module '@deepseek-ai/cordis' {
582
+ interface Context {
583
+ sessions: SessionStore;
584
+ }
585
+ interface Events {
586
+ /**
587
+ * Creation announcement during session publication. A synchronous throw vetoes and rolls
588
+ * back with a paired disposal; detach requested during dispatch is deferred.
589
+ * A returned-promise rejection is logged but cannot retroactively veto this
590
+ * synchronous boundary.
591
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners
592
+ * receive only sessions entered through that agent's context.
593
+ * @param session - the session just entered and announced.
594
+ * @mode emit
595
+ */
596
+ 'session/created'(this: Scoped<Session>, session: Session): void;
597
+ /**
598
+ * Emitted once when an announced session leaves the store, including
599
+ * publication rollback, but never for an entry whose creation announcement
600
+ * did not begin. Listener failures are logged and contained.
601
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`) reuses the owner scope.
602
+ * @param session - the session that is no longer live in the store.
603
+ * @mode emit
604
+ */
605
+ 'session/disposed'(this: Scoped<Session>, session: Session): void;
606
+ /**
607
+ * Post-commit, fire-and-forget append feed. The listener snapshot resolves
608
+ * before the log push, but callbacks run after it; observer failures are
609
+ * logged and contained without making the committed append fail.
610
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners
611
+ * receive only events from sessions entered through that agent's context.
612
+ * @param session - the session whose log grew.
613
+ * @param event - the appended event, exactly as recorded.
614
+ * @mode emit
615
+ */
616
+ 'session/event'(this: Scoped<Session>, session: Session, event: SessionEvent): void;
617
+ /**
618
+ * Awaited parallel durability checkpoint: every listener runs and the
619
+ * caller awaits all of them, with no waterfall veto. Scope-filtered dispatch
620
+ * (`@deepseek-ai/dsh-scope`) reuses the session's owner scope.
621
+ * @param session - the session whose buffered events must reach durable storage.
622
+ * @mode parallel
623
+ */
624
+ 'session/flush'(this: Scoped<Session>, session: Session): Promise<void> | void;
625
+ }
626
+ }
627
+ declare module '@deepseek-ai/dsh-typert-protocol' {
628
+ interface TypertLookupMap {
629
+ session: TypertLookup<Session, SessionId>;
630
+ }
631
+ }
632
+ /**
633
+ * An event-sourced session: an append-only log of {@link SessionEvent}s.
634
+ *
635
+ * Plain class (not a Service) — create live instances via
636
+ * `ctx.sessions.create()` and detached instances via {@link create}.
637
+ * Seeding with an existing event log replays/forks a session.
638
+ * @typert object
639
+ */
640
+ declare class Session {
641
+ #private;
642
+ private log;
643
+ /** Single incremental owner of surface acceptance and projection state. */
644
+ private readonly surfaceManager;
645
+ /** The ordered surface over this session's event log. */
646
+ get surface(): SessionSurface;
647
+ /**
648
+ * Detached, deep-frozen creation metadata (format version, cwd, lineage,
649
+ * and whether fork history exists). Supplied by the store via `ctx.sessions.create()`. When a
650
+ * `Session` is created without a store-owned header, a minimal header is
651
+ * synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so
652
+ * `session.header` is always present. Kept out of the event log — it is a
653
+ * storage concern, not replayable conversation state.
654
+ */
655
+ readonly header: SessionHeader;
656
+ /** Number of leading events inherited from this Session's fork parent. */
657
+ readonly inheritedEventCount: SessionLogOffset;
658
+ /** The session identity, derived from its durable header's single copy. */
659
+ get id(): SessionId;
660
+ /**
661
+ * The constructor seed length (0 without one), before any marker appended
662
+ * during construction. Seed events never publish on `session/event`. A
663
+ * marker appended before the store attaches occupies this seq without
664
+ * publishing either; otherwise this seq is available for the next append.
665
+ *
666
+ * This in-process offset is not persisted. A fork seed can already contain
667
+ * the child's inherited marker and synthetic closers, so its child-owned
668
+ * history starts at {@link inheritedEventCount}, before this offset. A
669
+ * resumed Session's seed contains its full stored log, while its inherited
670
+ * count keeps the durable fork cut. Consumers needing complete canonical
671
+ * history start at seq 0.
672
+ */
673
+ readonly firstLiveSeq: SessionLogOffset;
674
+ /**
675
+ * First event produced for this object lifecycle. A new fork includes its
676
+ * child-owned seed marker and closers; a restored Session starts after its
677
+ * complete stored prefix. This in-process capture offset is not persisted.
678
+ */
679
+ readonly firstLifecycleSeq: SessionLogOffset;
680
+ /**
681
+ * Create a detached session by validating and snapshotting borrowed seed
682
+ * events and storage metadata.
683
+ * @param id - session identity.
684
+ * @param seed - optional borrowed replay or fork events.
685
+ * @param header - optional borrowed storage metadata.
686
+ * @param inheritedEventCount - exact fork-inherited prefix length for a seeded header.
687
+ * @param projections - pure interpreters for plugin-owned message changes.
688
+ * @returns a detached session.
689
+ * @throws when a seed event requires a missing message interpreter or fails validation.
690
+ */
691
+ static create(id: SessionId, seed?: readonly SessionEvent[], header?: SessionHeader, inheritedEventCount?: SessionLogOffset, projections?: readonly SessionMessageProjection[]): Session;
692
+ /**
693
+ * Restore a detached session by adopting an independently owned or deeply frozen seed.
694
+ * Runtime-required event fields, event envelopes, sequence continuity, surface
695
+ * transitions, and header fields are validated without copying or freezing events.
696
+ * Embedded Assistant streams remain opaque until a stream consumer or storage
697
+ * verifier reads them.
698
+ * @param id - restored session identity.
699
+ * @param seed - independently owned or deeply frozen events.
700
+ * @param header - independently owned storage metadata.
701
+ * @param inheritedEventCount - exact fork-inherited prefix length decoded from storage.
702
+ * @param eventState - aliasing state carried from the operation that produced the seed.
703
+ * @param projections - pure interpreters for plugin-owned message changes.
704
+ * @returns a restored detached session.
705
+ * @throws when a seed event requires a missing message interpreter or fails validation.
706
+ */
707
+ static fromRestore(id: SessionId, seed: readonly SessionEvent[], header: SessionHeader, inheritedEventCount: SessionLogOffset, eventState: SessionSeedEventState, projections?: readonly SessionMessageProjection[]): Session;
708
+ private constructor();
709
+ /** Cached immutable full snapshot of the private append-only log. */
710
+ private eventsSnapshot;
711
+ /**
712
+ * Return the immutable event stored at one exact sequence number.
713
+ * @deprecated Existing logic may remain unmigrated for now, but new calls are prohibited.
714
+ * See the [Agent Note](../../../../.agents/notes/implemented/architecture/2026-09-09-deprecate-synchronous-session-event-reads.md).
715
+ * @param seq - event sequence number.
716
+ * @returns the accepted event, or undefined when the log does not contain it.
717
+ */
718
+ eventAt(seq: SessionSeq): SessionEvent | undefined;
719
+ /**
720
+ * Materialize an immutable snapshot of a half-open event sequence range.
721
+ * A full current snapshot is reused until the next append; every previously
722
+ * returned snapshot remains stable after later appends.
723
+ * @deprecated Existing logic may remain unmigrated for now, but new calls are prohibited.
724
+ * See the [Agent Note](../../../../.agents/notes/implemented/architecture/2026-09-09-deprecate-synchronous-session-event-reads.md).
725
+ * @param fromSeq - non-negative inclusive sequence number; defaults to the log start.
726
+ * @param toSeqExclusive - non-negative exclusive sequence number; defaults to the current end.
727
+ * @returns a frozen array of the selected deeply frozen events.
728
+ */
729
+ snapshotEvents(fromSeq?: SessionLogOffset, toSeqExclusive?: SessionLogOffset): readonly SessionEvent[];
730
+ /**
731
+ * Return this Session's events after its fork-inherited prefix.
732
+ * @deprecated Existing logic may remain unmigrated for now, but new calls are prohibited.
733
+ * See the [Agent Note](../../../../.agents/notes/implemented/architecture/2026-09-09-deprecate-synchronous-session-event-reads.md).
734
+ * @returns a fresh array containing child-owned events in log order.
735
+ */
736
+ ownEvents(): readonly SessionEvent[];
737
+ /**
738
+ * Whether one existing event position is outside the fork-inherited prefix.
739
+ * @param seq - event position in this Session.
740
+ * @returns true when the event belongs to this Session rather than its parent.
741
+ */
742
+ isOwnSeq(seq: SessionSeq): boolean;
743
+ /** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */
744
+ get seq(): SessionLogOffset;
745
+ /**
746
+ * Append one typed event to the log and synchronously notify observers via
747
+ * the store-owned, module-private publication hooks. The hot path never blocks
748
+ * on I/O — persistence plugins buffer asynchronously. Once the event enters
749
+ * the log, the append is committed: observer failures are logged and
750
+ * contained per listener, so they do not change the return value or prevent
751
+ * later listeners from observing the same accepted event.
752
+ *
753
+ * @param type - The event type (key of {@link SessionEventMap}).
754
+ * @param data - The event payload; must be JSON-serializable.
755
+ * @param opts - Surface metadata: `surfaceOp` controls how the event enters
756
+ * the ordered surface; `sourceEventSeqs` lists the seq numbers of earlier
757
+ * events this one derives from. REQUIRED for
758
+ * {@link SurfaceEventType} events (every message-producing event must
759
+ * declare how it joins the surface, the sole source of derived model
760
+ * history) and
761
+ * rejected by the compiler for non-surface types like `turn/start` or
762
+ * `assistant/attempt`. Assistant messages embed their exact provider
763
+ * stream and cannot cite top-level source events.
764
+ * @returns the logged event — its assigned `seq`/`time` plus the SNAPSHOT of
765
+ * `data` that entered the log, so reading `event.data` back sees the logged
766
+ * value, never the caller's still-mutable input.
767
+ * @throws if `data` or surface metadata is not losslessly JSON-serializable
768
+ * (BigInt, function, symbol, undefined, negative zero, non-finite number,
769
+ * circular reference, sparse array, or an exotic object such as
770
+ * Map/Set/Date/class instance), or when the candidate violates the
771
+ * request-header empty-field or tool-error consistency rules, or the
772
+ * canonical surface contract (marker shape and eligibility, unique
773
+ * earlier source-event references, positional replacement validity, and complete
774
+ * shadowed-node coverage). One iterative pass reads, validates, and
775
+ * copies each nested value once, so a stateful getter cannot supply one value
776
+ * to validation and another to storage. The event log is the durable source
777
+ * of truth, so a bad event fails at the append site rather than later during
778
+ * a backend flush. A synchronous internal dispatch validation failure or an
779
+ * append reentered while this acceptance/publication boundary is open also
780
+ * rejects before the log changes.
781
+ */
782
+ append<T extends SessionEventType>(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent<T>] : []): SessionEvent<T>;
783
+ /**
784
+ * Read the store attachment for one append, refusing an append that
785
+ * reenters while another append is being published.
786
+ * @returns the attachment, or undefined for a detached Session.
787
+ */
788
+ private publicationEntry;
789
+ /**
790
+ * Accept one frozen candidate at the next sequence number, enter it into the
791
+ * log, and notify `session/event` observers with per-listener containment.
792
+ * @param event - the candidate built at the current log length.
793
+ * @param entry - the attachment read before the candidate was built.
794
+ */
795
+ private commit;
796
+ /** Cached fold of the request-header events — see {@link requestHeader}. */
797
+ private headerFold;
798
+ /** Log position (events consumed) the header fold has reached. */
799
+ private headerFoldSeq;
800
+ /**
801
+ * The {@link EpochHeader} in force after the log's last header event — the
802
+ * header the NEXT request will be compared against — or undefined before
803
+ * the first `request/header` snapshot. The live, incrementally-maintained
804
+ * form of `foldRequestHeader(session.snapshotEvents())`: each header event is folded
805
+ * once, when first seen, so a per-step read costs O(new events).
806
+ * @returns the folded header, or undefined when no header event exists yet.
807
+ */
808
+ requestHeader(): EpochHeader | undefined;
809
+ /** Cached fold of `request/context` events. */
810
+ private contextFold;
811
+ private contextFoldSeq;
812
+ /**
813
+ * Return the latest resolved route metadata, or `undefined` before the first
814
+ * `request/context` event. Each event is folded once.
815
+ * @returns the latest immutable route metadata.
816
+ */
817
+ requestContext(): RequestContext | undefined;
818
+ /** Cached historical tool definitions and updates for request projection. */
819
+ private readonly toolHistoryProjection;
820
+ /** Index of the next committed event not yet consumed by the tool-history fold. */
821
+ private toolHistorySeq;
822
+ /**
823
+ * Fold unseen committed events into capability-independent tool history.
824
+ * Initial access reconstructs inherited history; later reads consume only new events.
825
+ * @returns an immutable snapshot for LLM request projection, including historical addition definitions.
826
+ */
827
+ toolHistory(): ToolHistory;
828
+ /** The derived-message cache: frozen projections, extended per unseen node. */
829
+ private derived;
830
+ /** Surface position (nodes projected) the cache has reached. */
831
+ private derivedNodes;
832
+ /** {@link SurfaceManager.contentGeneration} the cache was built under. */
833
+ private derivedGeneration;
834
+ /**
835
+ * Derive the LLM message history by walking the ordered sequences of
836
+ * message-producing events maintained by `surfaceOp` markers. The
837
+ * surface is the single source of derived history: every message-producing
838
+ * append records its `surfaceOp`, so a raw event with no marker (a chunk, a
839
+ * turn boundary) is correctly absent, and a compaction `replace` deletes the
840
+ * shadowed nodes from the derivation. The projection rules are
841
+ * {@link deriveEventMessage}, with logged message projections applied
842
+ * without changing node membership or message identity.
843
+ *
844
+ * CACHED: pure tail growth costs O(new nodes); a replacement or message projection
845
+ * ({@link SessionSurface.contentGeneration}) rebuilds. The returned array is
846
+ * a fresh snapshot per call (later appends never grow an array a caller
847
+ * already holds); the `Message` objects in it are SHARED and **deep-frozen**.
848
+ * Unchanged content reuses frozen event data; projected blocks are frozen
849
+ * derived copies. Consumers cannot mutate the log through either form.
850
+ * @returns a fresh array of the shared, frozen derived history.
851
+ */
852
+ deriveMessages(): Message[];
853
+ /**
854
+ * Project one event with all committed message projections applied.
855
+ * The original durable event remains unchanged.
856
+ * @param event - the event to project.
857
+ * @returns the derived message, or null when the event produces none.
858
+ */
859
+ deriveEventMessage(event: SessionEvent): Message | null;
860
+ }
861
+ /** A fork source: either the live session object or its live store id. */
862
+ type SessionForkSource = Session | SessionId;
863
+ /**
864
+ * In-memory session store (`ctx.sessions`).
865
+ *
866
+ * Persistence is intentionally not implemented here — the agent lifecycle
867
+ * attaches a session-log writer to each published session's write handle;
868
+ * a session published outside that lifecycle persists nothing.
869
+ */
870
+ declare class SessionStore extends Service {
871
+ private store;
872
+ private counter;
873
+ private readonly projections;
874
+ /** Borrowed definitions for detached replay; contributions live until their registering fibers unload. */
875
+ get messageProjections(): readonly SessionMessageProjection[];
876
+ /**
877
+ * Register one event interpreter for live creation, restore, and fork.
878
+ * Disposing the contribution makes sessions that used it refuse further derivation.
879
+ * @param projection - pure definition owned by the event's plugin.
880
+ * @returns the fiber-owned disposer.
881
+ * @throws when another definition already owns this event type.
882
+ */
883
+ registerMessageProjection(projection: SessionMessageProjection): () => Promise<void>;
884
+ constructor(ctx: Context);
885
+ /**
886
+ * Create a session owned by the calling fiber: disposing that fiber stops
887
+ * event notification and removes the session from the store. `options.seed`
888
+ * populates the session with a copy of those events (replay/fork);
889
+ * `options.meta` attaches creation metadata (validated absolute `cwd`, seed
890
+ * and parent lineage, and delegation depth) as the immutable
891
+ * {@link SessionHeader} (the store fills `version`/`id`/`createdAt`).
892
+ *
893
+ * For an agent whose session must be torn down IN ORDER with its loop (so the
894
+ * loop's final events are published before the store attachment ends), do NOT use this
895
+ * — fold the session lifecycle into the agent's own effect via
896
+ * {@link prepare} + {@link enter} + {@link announce} (see
897
+ * `dsh-agent-loop`'s creation transaction).
898
+ *
899
+ * @param id - the session id; omitted, the store mints `session-<n>`.
900
+ * @param options - seed events and/or creation metadata for the header.
901
+ * @returns the live session, already entered and announced.
902
+ * @throws if a session with `id` already exists, metadata is not a plain
903
+ * lossless-JSON record with valid scalar fields, or `meta.cwd` is a
904
+ * non-absolute path (storage backends key directories off it).
905
+ */
906
+ create(id?: SessionId, options?: CreateSessionOptions): Session;
907
+ /**
908
+ * Build a session WITHOUT entering it into the store — validate the id/cwd and
909
+ * construct the {@link Session} (with its immutable {@link SessionHeader}).
910
+ * Pairs with {@link enter} + {@link announce}: a caller that owns a composite
911
+ * `ctx.effect` (the agent factory) folds the session lifecycle into that ONE
912
+ * effect so a fiber unload tears the session + agent down as a single ORDERED
913
+ * chain rather than as racing sibling effects — which would remove the publication hooks
914
+ * before the driver's closing events commit, dropping them.
915
+ *
916
+ * @param id - the session id; omitted, the store mints `session-<n>`.
917
+ * @param options - seed events and/or creation metadata for the header. With
918
+ * `eventState`, every seed event is either independently owned or any
919
+ * shared value is deeply frozen; {@link Session.fromRestore} validates and
920
+ * adopts those values without copying or freezing them.
921
+ * @returns the constructed session, NOT yet in the store.
922
+ * @throws if a session with `id` already exists, metadata is not a plain
923
+ * lossless-JSON record with valid scalar fields, or `meta.cwd` is a
924
+ * non-absolute path.
925
+ */
926
+ prepare(id?: SessionId, options?: PrepareSessionOptions): Session;
927
+ /**
928
+ * Enter a {@link prepare}d session into the store: install the module-private
929
+ * append publication hooks and add it to the store. Returns the DETACH
930
+ * disposer (hooks + store removal). Does NOT emit `session/created` —
931
+ * the caller yields this disposer inside its effect and THEN calls
932
+ * {@link announce}, so a throwing `session/created` listener rolls the attach
933
+ * back instead of leaking it.
934
+ *
935
+ * Re-checks the id for a duplicate: `prepare` and `enter` are public
936
+ * cross-package primitives and a caller may interleave arbitrary work (or
937
+ * another create) between them, so a stale prepared session must NOT overwrite
938
+ * a live store entry of the same id — its detach disposer would later delete
939
+ * the REAL session. The {@link create} convenience and the agent factory call
940
+ * the two back-to-back so they never trip this, but the public API cannot
941
+ * assume that.
942
+ *
943
+ * @param session - a {@link prepare}d session not yet in the store.
944
+ * @returns the detach disposer (publication hooks + store removal). When called from
945
+ * a synchronous `session/created` listener, removal and disposal wait until
946
+ * that creation dispatch unwinds.
947
+ * @throws if a session with this id is already in the store.
948
+ */
949
+ enter(session: Session): () => void;
950
+ /** Remove one exact entered session and emit its paired disposal when announced. */
951
+ private detachEntered;
952
+ /** Emit `session/created` exactly once for an {@link enter}ed session (with
953
+ * the carrier {@link enter} captured). Separate from {@link enter} so the
954
+ * caller can yield the detach disposer first (rollback safety — see
955
+ * {@link enter}).
956
+ * @param session - the entered session to announce to listeners.
957
+ * @throws if the session is not live or its announcement already began,
958
+ * including a reentrant call from a creation listener. */
959
+ announce(session: Session): void;
960
+ /** Emit the paired teardown notification with per-listener containment. */
961
+ private emitDisposed;
962
+ /**
963
+ * Dispatch the awaited `session/flush` durability checkpoint for `session`,
964
+ * with the carrier captured at {@link enter}. THE flush entry point: the
965
+ * store owns the carrier, so callers (the checkpoint policy's per-request
966
+ * barrier, goal-round-driver's idle checkpoint, teardown drains, and consumers
967
+ * that flush themselves before reading storage) must come through here
968
+ * rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner
969
+ * and one spelling.
970
+ * @param session - the session whose buffered events must reach durable storage.
971
+ * @returns whether at least one durability listener participated, after every
972
+ * listener has settled successfully.
973
+ * @throws the first registered listener failure after every listener settles.
974
+ */
975
+ flush(session: Session): Promise<boolean>;
976
+ /** Return the exact live entry; detached/prepared objects reject. */
977
+ private liveEntryFor;
978
+ /**
979
+ * Look up a live session.
980
+ * @param id - the session id to look up.
981
+ * @returns the session, or undefined when no live session has that id.
982
+ */
983
+ get(id: SessionId): Session | undefined;
984
+ /**
985
+ * All live sessions, in creation order.
986
+ * @returns a fresh array; mutating it does not affect the store.
987
+ */
988
+ list(): Session[];
989
+ /**
990
+ * Create a live child session from an exact prefix of a live source.
991
+ * `boundary` is an inclusive source event seq; omitted means the source's
992
+ * current last event. An open tail receives synthetic tool results and
993
+ * step/turn closers with the forked cause. Closed steps and turns remain
994
+ * unchanged, including any failed tool calls already missing results.
995
+ * `inheritedEventCount` counts only copied source events, excluding these closers.
996
+ *
997
+ * @param source - Live source session object or id.
998
+ * @param boundary - Inclusive source event seq to fork through; omitted means
999
+ * the source's current last event, and omitted on an empty source forks an
1000
+ * empty child.
1001
+ * @param childSessionId - Optional child session id; omitted delegates to
1002
+ * `SessionStore`'s id policy.
1003
+ * @returns The created live child session.
1004
+ */
1005
+ fork(source: SessionForkSource, boundary?: SessionSeq, childSessionId?: SessionId): Session;
1006
+ private _forkBoundary;
1007
+ private _resolveForkSource;
1008
+ }
1009
+ //#endregion
1010
+ //#region src/core/sync/session-sync.d.ts
1011
+ interface SpillTransferReference {
1012
+ owner: {
1013
+ sessionId: string;
1014
+ };
1015
+ source: {
1016
+ toolName: string;
1017
+ callId: string;
1018
+ label: string;
1019
+ };
1020
+ suggestedName: string;
1021
+ ref: {
1022
+ locator: string;
1023
+ bytes?: number;
1024
+ retrievalHint: string;
1025
+ };
1026
+ }
1027
+ interface SyncSessionWorkspace {
1028
+ originInstanceId: string;
1029
+ originWorkspaceId: string;
1030
+ nodeOrigin: SyncOrigin;
1031
+ remotePath: string;
1032
+ title: string;
1033
+ revision: SyncRevision;
1034
+ contentDigest: string;
1035
+ }
1036
+ interface SyncSessionInstructionSnapshot {
1037
+ text: string;
1038
+ capturedAt: string;
1039
+ workspaceOrigin?: SyncOrigin;
1040
+ workspaceRemotePath?: string;
1041
+ workspaceRevision?: number;
1042
+ digest?: string;
1043
+ inheritedFromOrigin?: SyncOrigin;
1044
+ }
1045
+ type SyncSessionObject = {
1046
+ id: string;
1047
+ kind: 'image';
1048
+ ref: ImageAttachmentRef;
1049
+ bytes: number;
1050
+ digest: string;
1051
+ data: string;
1052
+ } | {
1053
+ id: string;
1054
+ kind: 'file';
1055
+ ref: FileAttachmentRef;
1056
+ bytes: number;
1057
+ digest: string;
1058
+ data: string;
1059
+ } | {
1060
+ id: string;
1061
+ kind: 'spill';
1062
+ reference: SpillTransferReference;
1063
+ bytes: number;
1064
+ digest: string;
1065
+ data: string;
1066
+ unavailable?: boolean;
1067
+ };
1068
+ interface SyncSessionEntry {
1069
+ metadata: SyncRecordMetadata;
1070
+ branchId?: string;
1071
+ sourceLocalSessionId?: string;
1072
+ header?: SessionHeader;
1073
+ inheritedEventCount?: number;
1074
+ parentOrigin?: SyncOrigin;
1075
+ workspace?: SyncSessionWorkspace;
1076
+ workspacePosition?: number;
1077
+ archived?: boolean;
1078
+ pinned?: boolean;
1079
+ instructionSnapshot?: SyncSessionInstructionSnapshot;
1080
+ events?: SessionEvent[];
1081
+ objects?: SyncSessionObject[];
1082
+ }
1083
+ interface SyncSessionBundle {
1084
+ protocolVersion: 1;
1085
+ instanceId: string;
1086
+ entries: SyncSessionEntry[];
1087
+ skipped: Array<{
1088
+ sessionId: string;
1089
+ reason: string;
1090
+ }>;
1091
+ digest: string;
1092
+ }
1093
+ interface SyncSessionApplyResult {
1094
+ created: number;
1095
+ updated: number;
1096
+ archived: number;
1097
+ deleted: number;
1098
+ skipped: number;
1099
+ unmapped: number;
1100
+ }
1101
+ interface SyncSessionApplyOptions {
1102
+ importedVia?: SyncImportMethod;
1103
+ allowSameInstance?: boolean;
1104
+ }
1105
+ interface SyncSessionTransferPlan {
1106
+ toLocal: SyncSessionEntry[];
1107
+ toRemote: SyncSessionEntry[];
1108
+ skipped: number;
1109
+ }
1110
+ declare class SyncSessionError extends Error {
1111
+ readonly code: string;
1112
+ constructor(code: string, message: string, cause?: unknown);
1113
+ }
1114
+ interface SessionSnapshotLike {
1115
+ header: SessionHeader;
1116
+ formatStatus?: 'current' | 'migration-required';
1117
+ revision: unknown;
1118
+ eventCount?: number;
1119
+ }
1120
+ interface SessionHandleLike {
1121
+ readonly id: SessionId;
1122
+ readonly header: SessionHeader;
1123
+ readonly inheritedEventCount: number;
1124
+ read(offset?: number, length?: number): Promise<{
1125
+ events: readonly SessionEvent[];
1126
+ }>;
1127
+ append(events: readonly SessionEvent[]): Promise<void>;
1128
+ flush(): Promise<void>;
1129
+ close(): Promise<void>;
1130
+ }
1131
+ interface SessionPersistenceLike {
1132
+ flush(): Promise<void>;
1133
+ list(): Promise<readonly SessionSnapshotLike[]>;
1134
+ stat(id: SessionId): Promise<SessionSnapshotLike | undefined>;
1135
+ open(id: SessionId, access: 'read' | 'write'): Promise<SessionHandleLike>;
1136
+ create(header: SessionHeader, options?: {
1137
+ inheritedEventCount?: number;
1138
+ }): Promise<SessionHandleLike>;
1139
+ }
1140
+ interface WorkspaceLike {
1141
+ id: string;
1142
+ path: string;
1143
+ title: string;
1144
+ sessionIds: readonly SessionId[];
1145
+ setTitle(title: string): Promise<void>;
1146
+ attachSession(sessionId: SessionId): Promise<void>;
1147
+ insertSessionBefore(sessionId: SessionId, beforeSessionId?: SessionId): Promise<void>;
1148
+ }
1149
+ interface WorkspaceRegistryLike {
1150
+ list(): WorkspaceLike[];
1151
+ get(id: string): WorkspaceLike | undefined;
1152
+ create(path: string, title?: string): Promise<WorkspaceLike>;
1153
+ archiveSession(sessionId: SessionId, options?: {
1154
+ stopActivity?: boolean;
1155
+ }): Promise<void>;
1156
+ unarchiveSession(sessionId: SessionId): Promise<void>;
1157
+ pinSession?(sessionId: SessionId): Promise<void>;
1158
+ unpinSession?(sessionId: SessionId): Promise<void>;
1159
+ readonly archivedSessionIds: readonly SessionId[];
1160
+ readonly pinnedSessionIds?: readonly SessionId[];
1161
+ }
1162
+ interface AttachmentStoreLike {
1163
+ readImage(ref: ImageAttachmentRef): Promise<{
1164
+ ref: ImageAttachmentRef;
1165
+ data: Uint8Array;
1166
+ }>;
1167
+ saveImage(input: {
1168
+ data: Uint8Array;
1169
+ mediaType: ImageAttachmentRef['mediaType'];
1170
+ name?: string;
1171
+ }): Promise<ImageAttachmentRef>;
1172
+ readFileStream(ref: FileAttachmentRef): AsyncIterable<Uint8Array>;
1173
+ saveFileStream(input: {
1174
+ data: AsyncIterable<Uint8Array>;
1175
+ name?: string;
1176
+ }): Promise<FileAttachmentRef>;
1177
+ }
1178
+ interface SpillStoreLike {
1179
+ root?: string;
1180
+ readTextStream?(input: {
1181
+ owner: {
1182
+ sessionId: SessionId;
1183
+ };
1184
+ ref: SpillTransferReference['ref'];
1185
+ }): AsyncIterable<Uint8Array>;
1186
+ saveTextStream?(input: {
1187
+ owner: {
1188
+ sessionId: SessionId;
1189
+ };
1190
+ source: SpillTransferReference['source'];
1191
+ suggestedName: string;
1192
+ transferId: string;
1193
+ bytes: number;
1194
+ digest: string;
1195
+ content: AsyncIterable<Uint8Array>;
1196
+ }): Promise<SpillTransferReference['ref']>;
1197
+ }
1198
+ declare function planSessionTransfers(direction: 'pull' | 'bidirectional', localEntries: readonly SyncSessionEntry[], remoteEntries: readonly SyncSessionEntry[]): SyncSessionTransferPlan;
1199
+ declare function validateSyncSessionBundle(value: unknown): SyncSessionBundle;
1200
+ declare function makeSyncSessionBundle(instanceId: string, entries: SyncSessionEntry[], skipped?: Array<{
1201
+ sessionId: string;
1202
+ reason: string;
1203
+ }>): SyncSessionBundle;
1204
+ declare class SyncSessionService {
1205
+ private readonly state;
1206
+ private readonly nodes;
1207
+ private readonly registry;
1208
+ private readonly bindings;
1209
+ private readonly getWorkspaces;
1210
+ private readonly getPersistence;
1211
+ private readonly getAttachments;
1212
+ private readonly getSpills;
1213
+ private readonly instructions;
1214
+ private readonly journal;
1215
+ private readonly now;
1216
+ private operationTail;
1217
+ constructor(state: SyncStateStore, nodes: SyncNodeService, registry: NodeRegistry, bindings: WorkspaceBindingsStore, getWorkspaces: () => WorkspaceRegistryLike | undefined, getPersistence: () => SessionPersistenceLike | undefined, getAttachments: () => AttachmentStoreLike | undefined, getSpills: () => SpillStoreLike | undefined, instructions: SessionInstructionSnapshotStore, journal?: SyncSessionJournalStore, now?: () => number);
1218
+ exportBundle(): Promise<SyncSessionBundle>;
1219
+ applyBundle(value: unknown, sourceName: string, peerId?: string, options?: SyncSessionApplyOptions): Promise<SyncSessionApplyResult>;
1220
+ preflightBundle(value: unknown, options?: SyncSessionApplyOptions): void;
1221
+ pendingPeerIds(): string[];
1222
+ recoverPending(): Promise<void>;
1223
+ cleanupOrphanedStaging(): void;
1224
+ listArchives(): SyncSessionArchive[];
1225
+ restoreArchive(branchId: string): Promise<SessionId>;
1226
+ private exportBundleNow;
1227
+ private applyBundleNow;
1228
+ private prepareEntry;
1229
+ private ensureWorkspace;
1230
+ private importObjects;
1231
+ private rewriteEvents;
1232
+ private validatePrepared;
1233
+ private applyPrepared;
1234
+ private applyMembershipOnly;
1235
+ private applyArchiveStateOnly;
1236
+ private archiveCurrent;
1237
+ private applyTombstone;
1238
+ private restoreArchiveNow;
1239
+ private orderWorkspaceSessions;
1240
+ private localSessionIdForOrigin;
1241
+ private localWorkspaceIdForOrigin;
1242
+ private writeSession;
1243
+ private workspaceDescriptor;
1244
+ private exportSessionEntry;
1245
+ private readStableSession;
1246
+ private exportObjects;
1247
+ private requirePersistence;
1248
+ private serializeMutation;
1249
+ }
1250
+ //#endregion
1251
+ export { SyncSessionError as a, SyncSessionService as c, WorkspaceRegistryLike as d, makeSyncSessionBundle as f, SyncSessionEntry as i, SyncSessionTransferPlan as l, validateSyncSessionBundle as m, SyncSessionApplyResult as n, SyncSessionInstructionSnapshot as o, planSessionTransfers as p, SyncSessionBundle as r, SyncSessionObject as s, SyncSessionApplyOptions as t, SyncSessionWorkspace as u };
1252
+ //# sourceMappingURL=session-sync-g6qKZzjV.d.ts.map