dsh-pause-session 0.0.0-stage → 0.1.0

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,47 @@
1
+ /**
2
+ * The message history a session's log derives to, and the one rule that reads
3
+ * whether it still owes the model an answer.
4
+ *
5
+ * That question is asked twice and must have one answer: the clean wake asks it
6
+ * before it hands a session an input (an input nobody owes an answer to would
7
+ * open a turn of its own), and the decision list publishes it as the row's
8
+ * `wake` field. A published promise that the wake then declines to keep is the
9
+ * report lying, so both read the same derivation and the same rule.
10
+ *
11
+ * The derivation is the harness's own: the surface fold the loop reads its
12
+ * history through, with the same message projections this process has
13
+ * registered, and an interrupted tail closed exactly as the harness closes it
14
+ * on the next read. `resume.ts` reads the live form of it
15
+ * (`Session.deriveMessages()`); {@link derivedHistory} is the cold form over a
16
+ * stored log, which is all the decision list may claim — it opens a log to read
17
+ * it and never activates a session.
18
+ * @module dsh-pause-session/history
19
+ */
20
+ import type { Message } from '@deepseek-ai/dsh-llm';
21
+ import type { SessionEvent, SessionMessageProjection } from '@deepseek-ai/dsh-session';
22
+ /**
23
+ * Whether one derived history ends owing the model an answer: the last thing
24
+ * said on the model-visible surface is not an assistant message.
25
+ * @param messages - a derived history, in model-visible order.
26
+ * @returns whether a model still owes that history a reply.
27
+ */
28
+ export declare function owesReply(messages: readonly Message[]): boolean;
29
+ /**
30
+ * The messages one stored log derives to, as the harness would read them on the
31
+ * session's next activation: the open tail turn is closed with the harness's
32
+ * own synthetic results first, then the log is folded into its surface.
33
+ * @param events - the stored events, exactly as they are stored and in sequence order.
34
+ * @param projections - this process's registered message projections.
35
+ * @returns the derived history, in model-visible order.
36
+ * @throws when the log cannot be folded — an event this build has no interpreter
37
+ * for, or surface metadata that does not apply to this history.
38
+ */
39
+ export declare function derivedHistory(events: readonly SessionEvent[], projections: readonly SessionMessageProjection[]): Message[];
40
+ /**
41
+ * Whether one stored log names the route a wake would be addressed to. The wake
42
+ * needs a provider and a model to build a request at all, and the request
43
+ * header the session itself persisted is the only place that names them.
44
+ * @param events - the stored events, in sequence order.
45
+ * @returns whether the log's last request header carries both route fields.
46
+ */
47
+ export declare function routeNamed(events: readonly SessionEvent[]): boolean;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Host half of dsh-pause-session.
3
+ *
4
+ * Mounts the pause gate — the per-session hold at the model-request waterfall —
5
+ * the activity fold the park predicate reads, the durable park registry, the
6
+ * session control the browser half drives, and the clean resume path that
7
+ * answers the input a parked session left pending.
8
+ *
9
+ * The registry is read before anything is gated, so a session a previous
10
+ * process left parked is held again by this one without any user action; a
11
+ * registry this build cannot read fails the mount loudly rather than silently
12
+ * resuming every session it named.
13
+ * @module dsh-pause-session
14
+ */
15
+ import { z } from 'zod';
16
+ import type { Context } from '@deepseek-ai/cordis';
17
+ /** Plugin name; the Loader row and the bundle patch both use it. */
18
+ export declare const name = "dsh-pause-session";
19
+ /**
20
+ * Required host services: the model runtime to gate, the stores the control
21
+ * needs, the projection registry the park predicate reads turn state from, and
22
+ * the profile's storage, which holds the pause registry.
23
+ */
24
+ export declare const inject: string[];
25
+ /**
26
+ * Provider routes whose request conversion drops an empty user message, so the
27
+ * clean resume path's wake input never reaches the model on them.
28
+ *
29
+ * The list is deployment knowledge, not a constant this plugin may assume:
30
+ * whether an empty user message survives is decided by the adapter (and, for
31
+ * the pi-ai family, by the provider API that adapter is configured for), and a
32
+ * plugin cannot introspect an adapter. The default names the routes the shipped
33
+ * DeepSeek adapter registers; a profile that routes a session elsewhere gets
34
+ * the visible marker instead of a silent empty turn until it declares that
35
+ * route here.
36
+ */
37
+ export declare const DEFAULT_SILENT_WAKE_ROUTES: readonly ["deepseek-official", "deepseek-account"];
38
+ /** Validated plugin configuration. */
39
+ declare const ConfigShape: z.ZodObject<{
40
+ silentWakeRoutes: z.ZodDefault<z.ZodArray<z.ZodString>>;
41
+ maxListedLogEvents: z.ZodDefault<z.ZodNumber>;
42
+ }, z.core.$strip>;
43
+ /** Validated plugin configuration. */
44
+ export type Config = z.infer<typeof ConfigShape>;
45
+ /**
46
+ * The Loader hands a row's config through this schema, and an empty row config
47
+ * arrives as `undefined`; folding it to `{}` first is what lets the field
48
+ * defaults above apply instead of failing the mount.
49
+ */
50
+ export declare const Config: z.ZodPreprocess<z.ZodObject<{
51
+ silentWakeRoutes: z.ZodDefault<z.ZodArray<z.ZodString>>;
52
+ maxListedLogEvents: z.ZodDefault<z.ZodNumber>;
53
+ }, z.core.$strip>>;
54
+ /**
55
+ * Mount the durable pause registry, the pause gate, the activity fold, their
56
+ * session control, and the clean resume path.
57
+ *
58
+ * The registry opens first on purpose: if it cannot be read, nothing else is
59
+ * registered, so a failed mount leaves no half-installed control behind.
60
+ * @param ctx - the plugin's host context.
61
+ * @param config - validated route knowledge for the resume path's wake content.
62
+ */
63
+ export declare function apply(ctx: Context, config?: Config): Promise<void>;
64
+ export {};
@@ -0,0 +1,50 @@
1
+ /**
2
+ * What a session is doing between "pause was asked for" and "its next model
3
+ * request is standing still at the gate".
4
+ *
5
+ * Two facts decide that, and each has its own owner:
6
+ *
7
+ * - Whether a turn is open is derived state the harness already maintains:
8
+ * the agent registry owns the `turnBoundary` session projection, which folds
9
+ * `turn/start`, `turn/end`, `step/start`, and `step/end` into
10
+ * `openTurnStartSeq`. Reading it through `ctx.agents` is a synchronous
11
+ * projection read, not a scan of the event log (synchronous history reads are
12
+ * prohibited for new code).
13
+ * - Which tool is in flight is a log-derived per-session fact, so it is a
14
+ * session projection too. The projection folds each committed
15
+ * `tool/call` → `tool/result` pairing and keeps the calls in order; the
16
+ * framework owns replay, caching, and disposal. This module listens only to
17
+ * committed events so it can wake the control, never to keep a second copy
18
+ * of the state itself.
19
+ * @module dsh-pause-session/park
20
+ */
21
+ import type { Context } from '@deepseek-ai/cordis';
22
+ import type { SessionId } from '@deepseek-ai/dsh-session';
23
+ /** One session's current activity, as the control reports it. */
24
+ export interface ParkActivity {
25
+ /** Whether the session is inside a turn — including one waiting for this very park. */
26
+ readonly turnOpen: boolean;
27
+ /** Names of the calls currently in flight, in call order; empty when no tool is running. */
28
+ readonly runningTools: readonly string[];
29
+ }
30
+ /** Both halves of the activity question for one session. */
31
+ export interface ParkWatch {
32
+ /**
33
+ * @param sessionId - session to inspect.
34
+ * @returns the session's current turn and tool activity.
35
+ */
36
+ activity(sessionId: SessionId): ParkActivity;
37
+ /**
38
+ * Subscribe to activity changes.
39
+ * @param listener - called with the session whose activity changed; it must
40
+ * only record that a look is owed, never re-enter the session.
41
+ * @returns the unsubscribe function.
42
+ */
43
+ onChange(listener: (sessionId: SessionId) => void): () => void;
44
+ }
45
+ /**
46
+ * Mount the per-session activity projection and its notification edge.
47
+ * @param ctx - host context carrying the session store and the projection registry.
48
+ * @returns the watch the park state is derived from.
49
+ */
50
+ export declare function mountParkWatch(ctx: Context): Promise<ParkWatch>;
@@ -0,0 +1,117 @@
1
+ /**
2
+ * The durable park registry: which sessions are paused, and how cleanly each
3
+ * one stopped.
4
+ *
5
+ * The registry lives in the profile's storage — `ctx.storageDomain`, the
6
+ * schema-validated domain data form over whichever backend the composition
7
+ * routes it to — and never in the session log: a pause is not part of a
8
+ * session's history, and the list has to be readable by a process that has not
9
+ * opened any session yet. The domain's own backend route is configuration, so
10
+ * this module names no path and performs no IO of its own.
11
+ *
12
+ * The domain keeps the DEFAULT whole-unit layout on purpose. The per-record
13
+ * layout reads a malformed or stale record document as an absent record, which
14
+ * here would silently drop one paused session; a whole-unit file turns any
15
+ * corruption into a failed `open`, and a failed open fails the plugin's mount
16
+ * loudly instead of resuming everything.
17
+ * @module dsh-pause-session/registry
18
+ */
19
+ import { z } from 'zod';
20
+ import type { Context } from '@deepseek-ai/cordis';
21
+ import type { SessionId } from '@deepseek-ai/dsh-session';
22
+ import type { ParkPhase } from './shared.js';
23
+ /** Domain and backend-unit name; one document per profile under the storage root. */
24
+ export declare const PARK_REGISTRY_DOMAIN = "pause_registry";
25
+ /** One session's stored park outcome. */
26
+ export declare const parkRecord: z.ZodObject<{
27
+ phase: z.ZodEnum<{
28
+ draining: "draining";
29
+ parking: "parking";
30
+ safe: "safe";
31
+ "flush-failed": "flush-failed";
32
+ }>;
33
+ updatedAt: z.ZodNumber;
34
+ rearmGoal: z.ZodDefault<z.ZodBoolean>;
35
+ }, z.core.$strip>;
36
+ /** One session's stored park outcome. */
37
+ export type ParkRecord = z.infer<typeof parkRecord>;
38
+ /**
39
+ * The registry declaration. `version: 1` and no `compatibleVersions`: the
40
+ * domain layer rejects a stored unit stamped with any other version rather than
41
+ * migrating it, so an unrecognized registry fails loud at open. Validation is
42
+ * the rejecting default for the same reason — a record this build cannot read
43
+ * must stop the mount, not disappear from the list.
44
+ */
45
+ export declare const parkRegistryDomain: {
46
+ name: string;
47
+ version: number;
48
+ tables: {
49
+ sessions: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<SessionId, {
50
+ phase: "draining" | "parking" | "safe" | "flush-failed";
51
+ updatedAt: number;
52
+ rearmGoal: boolean;
53
+ }>;
54
+ };
55
+ };
56
+ /** One session the registry remembers. */
57
+ export interface ParkedSession {
58
+ readonly sessionId: SessionId;
59
+ readonly phase: ParkPhase;
60
+ /** When the phase was written. */
61
+ readonly updatedAt: number;
62
+ /** Whether resuming this session may re-arm its goal; see {@link parkRecord}. */
63
+ readonly rearmGoal: boolean;
64
+ }
65
+ /** The durable pause list, opened over the profile's storage. */
66
+ export interface ParkRegistry {
67
+ /**
68
+ * @returns every remembered session, in insertion order.
69
+ */
70
+ list(): readonly ParkedSession[];
71
+ /**
72
+ * The same list as {@link list}, as a lazily kept read-only view.
73
+ *
74
+ * The whole-app aggregate and the decision list read this once per status
75
+ * read, and a status read can happen on every command-registry change; the
76
+ * view is rebuilt only when the stored entries actually changed, so a read
77
+ * that changes nothing does not build a second copy of the list to look at.
78
+ * A caller must not mutate it.
79
+ */
80
+ readonly parked: ReadonlyMap<SessionId, ParkedSession>;
81
+ /**
82
+ * @param sessionId - session to look up.
83
+ * @returns the remembered session, or `undefined` when nothing is parked under that id.
84
+ */
85
+ get(sessionId: SessionId): ParkedSession | undefined;
86
+ /**
87
+ * Write one session's outcome; resolves once it is durable. The goal opt-out
88
+ * already recorded for that session survives a phase change — the phases of
89
+ * one park episode all describe the same parked session.
90
+ * @param sessionId - the session being parked.
91
+ * @param phase - how far the park has got.
92
+ */
93
+ record(sessionId: SessionId, phase: ParkPhase): Promise<void>;
94
+ /**
95
+ * Set one session's goal opt-out; resolves once it is durable.
96
+ * @param sessionId - the parked session to change.
97
+ * @param rearmGoal - whether the clean resume path may re-arm its goal.
98
+ * @throws when no record exists for that session — the flag describes a
99
+ * parked session, and inventing a record would invent a park.
100
+ */
101
+ setRearmGoal(sessionId: SessionId, rearmGoal: boolean): Promise<void>;
102
+ /**
103
+ * Drop one session from the list, so a later process does not re-hold it.
104
+ * @param sessionId - the session being released.
105
+ */
106
+ forget(sessionId: SessionId): Promise<void>;
107
+ }
108
+ /**
109
+ * Open the registry over the mounted storage. The caller owns the handle's
110
+ * lifetime; this registers the close as an effect on `ctx`, so the unit is
111
+ * released with the plugin.
112
+ * @param ctx - plugin context carrying `storageDomain`.
113
+ * @returns the open registry.
114
+ * @throws whatever `open` rejects with — a `StorageError` for an unreadable
115
+ * unit, a `DomainError('invalid-record')` for a record this build cannot read.
116
+ */
117
+ export declare function openParkRegistry(ctx: Context): Promise<ParkRegistry>;
@@ -0,0 +1,221 @@
1
+ /**
2
+ * The clean resume path: bring back a session a previous process parked, and
3
+ * let it answer the input that was already pending when it stopped.
4
+ *
5
+ * A resume invents no turn. At the park point the loop had claimed the
6
+ * session's pending input onto the surface and built the request the gate then
7
+ * held; after a restart that input is still the last thing the session says and
8
+ * the model still owes it an answer. What is missing is only a reason for the
9
+ * loop to build a request again, and the documented way to ask for one is a
10
+ * wake input — a user message the loop claims.
11
+ *
12
+ * The wake is invisible only on the routes the composition declares in
13
+ * `silentWakeRoutes`, whose conversion drops an empty user message. On every
14
+ * other route the loop's request carries one visible marker instead, and the
15
+ * marker reaches the model; that is an accepted cost of resuming at all.
16
+ * Whether an empty user message survives is a property of the route's
17
+ * conversion rather than of the loop, so the route is resolved per session —
18
+ * from the request header the session itself persisted.
19
+ *
20
+ * The wake message is attributed to this plugin, never to the user: it is text
21
+ * this module synthesized on the session's behalf, in the session's own log and
22
+ * in front of the model, and a downstream consumer has to be able to tell it
23
+ * apart from something the human typed.
24
+ *
25
+ * Only a cleanly parked session takes this path. A record that never reached
26
+ * the park point, or whose flush did not finish, describes work whose durable
27
+ * state nobody knows; waking it would spend its owner's money on a guess, and
28
+ * deciding those sessions is the morning list's job, not this path's. That
29
+ * holds whether or not the recorded session happens to be live in this process:
30
+ * liveness is not the park outcome, and a session can be live without ever
31
+ * having stopped.
32
+ * @module dsh-pause-session/resume
33
+ */
34
+ import type { Context } from '@deepseek-ai/cordis';
35
+ import type { CommandResult } from '@deepseek-ai/dsh-commands';
36
+ import type { SessionId } from '@deepseek-ai/dsh-session';
37
+ import type { PauseGate } from './gate.js';
38
+ import type { ParkRegistry } from './registry.js';
39
+ declare module '@deepseek-ai/dsh-llm' {
40
+ interface MessageSourceMap {
41
+ /**
42
+ * Text dsh-pause-session synthesized on the session's behalf: the wake this
43
+ * path delivers and the unknown-outcome note a decision adds. Declared so
44
+ * the log, and anything reading it, can tell plugin-authored input from the
45
+ * user's own.
46
+ */
47
+ 'pause': {
48
+ kind: 'pause';
49
+ };
50
+ }
51
+ }
52
+ /**
53
+ * The one wake content a route that keeps an empty user message is given. It
54
+ * names its producer, because it lands in the same user turn as the input the
55
+ * model owes an answer to and must not read as part of it.
56
+ */
57
+ export declare const WAKE_MARKER = "[pause: resumed from a pause]";
58
+ /**
59
+ * How one resume asks the loop for the request it owes the session:
60
+ *
61
+ * - `silent`: the clean path's wake — an empty input on a route the
62
+ * composition declared silent, and the visible marker on any other route.
63
+ * - `message`: the decision list's "continue, and say the tool outcome is
64
+ * unknown" — user-visible text on the wire by construction, and the only
65
+ * resume that is not invisible.
66
+ * - `none`: no wake at all. This is what "leave it for me to read" costs: the
67
+ * session is not activated, nothing is asked of the model, and the park is
68
+ * exactly as it was.
69
+ */
70
+ export type WakeRequest = {
71
+ readonly kind: 'silent';
72
+ } | {
73
+ readonly kind: 'message';
74
+ readonly text: string;
75
+ } | {
76
+ readonly kind: 'none';
77
+ };
78
+ /** Result copy for a resumed session; the model never sees it. */
79
+ export declare const RESUMED_TEXT = "This session resumed from where it paused.";
80
+ /**
81
+ * Result copy for a registered session this path refuses: its durable state is
82
+ * not the outcome of a completed park, so waking it would be a guess.
83
+ */
84
+ export declare const UNCLEAN_TEXT: string;
85
+ /** Result copy when nothing is parked under that session. */
86
+ export declare const NOT_PARKED_TEXT = "pause has no pause recorded for this session.";
87
+ /** Result copy for a session that is parked but could not be loaded back. */
88
+ export declare const ACTIVATION_FAILED_TEXT = "pause could not reopen this session, so it stayed paused.";
89
+ /** Result copy for a one-shot subagent route: its Session exists, but no resume may reactivate it. */
90
+ export declare const UNRESUMABLE_TEXT = "pause did not resume this session: it is a one-shot subagent route and cannot be resumed.";
91
+ /**
92
+ * Result copy for the review decision. It is the one answer that promises
93
+ * nothing happened, because opening a session to read it is the user's own
94
+ * action in their session list — and activating its agent here would start a
95
+ * session they asked only to look at.
96
+ */
97
+ export declare const REVIEW_TEXT: string;
98
+ /** Result copy for a change the durable registry refused to record. */
99
+ export declare const UNRECORDED_TEXT = "pause could not write the pause registry, so it did not change the pause state.";
100
+ /** Copy for one goal opt-out change. */
101
+ export declare const REARM_GOAL_ON_TEXT = "pause will re-open this session's goal when it resumes it.";
102
+ export declare const REARM_GOAL_OFF_TEXT = "pause will leave this session's goal closed when it resumes it.";
103
+ /** Why one record did not produce a running session. */
104
+ export type ResumeRefusal = 'not-parked' | 'not-clean' | 'activation-failed' | 'unrecorded' | 'not-activated' | 'unresumable';
105
+ /** What one resume attempt did. */
106
+ export interface ResumeOutcome {
107
+ readonly sessionId: SessionId;
108
+ /** Whether the session is now running from the point it stopped. */
109
+ readonly resumed: boolean;
110
+ /** Present exactly when `resumed` is false. */
111
+ readonly refusal?: ResumeRefusal;
112
+ }
113
+ /** One resume attempt plus the answer the command that asked for it receives. */
114
+ export interface ResumeAttempt extends ResumeOutcome {
115
+ readonly answer: CommandResult;
116
+ }
117
+ /** How this path is wired into the session control that owns the pause state. */
118
+ export interface ResumeDeps {
119
+ /**
120
+ * Take a live session's pause back: the durable record goes first, then the
121
+ * gate. Owned by the session control so there is one release order.
122
+ */
123
+ release(sessionId: SessionId, text: string): Promise<CommandResult>;
124
+ /**
125
+ * Whether the pause this process holds was adopted from the registry rather
126
+ * than pressed here. Only an adopted pause is a restart: a press this process
127
+ * made and took back must never wake a model.
128
+ */
129
+ adopted(sessionId: SessionId): boolean;
130
+ }
131
+ /** Route knowledge this path needs from the composition. */
132
+ export interface ResumeOptions {
133
+ /**
134
+ * Provider routes whose request conversion drops an empty user message, so an
135
+ * empty wake never reaches the model. Deployment-owned because it is a
136
+ * property of the adapter behind each route, and a third-party plugin cannot
137
+ * introspect an adapter.
138
+ */
139
+ readonly silentWakeRoutes: readonly string[];
140
+ }
141
+ /** The clean resume path, as the session control drives it. */
142
+ export interface ResumePath {
143
+ /**
144
+ * Resume one session the registry remembers.
145
+ * @param sessionId - the session to resume.
146
+ * @param request - which wake this resume delivers; see {@link WakeRequest}.
147
+ * @param parentId - the direct parent a batch release already brought back, when there is one.
148
+ * @param signal - cancellation for the cold load and setup.
149
+ * @returns what happened, and the copy for whoever asked.
150
+ */
151
+ resumeSession(sessionId: SessionId, request: WakeRequest, parentId?: SessionId, signal?: AbortSignal): Promise<ResumeAttempt>;
152
+ /**
153
+ * Resume one session the decision list officially owns — a record that is
154
+ * known NOT to be clean, which the clean path above must refuse and this entry
155
+ * exists to carry out. Same release order, same wake vocabulary.
156
+ * @param sessionId - the listed session to bring back.
157
+ * @param request - which wake the decision delivers; see {@link WakeRequest}.
158
+ * @param finalize - whether the decision continues the session (`'release'`)
159
+ * or only answers it (`'review'`). A review activates nothing and writes
160
+ * nothing: opening a session to read it is the user's own action, not this
161
+ * plugin's.
162
+ * @param parentId - the direct parent a batch release already brought back, when there is one.
163
+ * @param signal - cancellation for the cold load and setup.
164
+ * @returns what happened, and the copy for whoever asked.
165
+ */
166
+ decideUnclean(sessionId: SessionId, request: WakeRequest, finalize: 'release' | 'review', parentId?: SessionId, signal?: AbortSignal): Promise<ResumeAttempt>;
167
+ /**
168
+ * Resume every session the registry remembers, clean ones only. One session's
169
+ * failure never stops the others.
170
+ * @param signal - cancellation checked between release levels and forwarded to each load.
171
+ * @returns one attempt per recorded session, in registry order.
172
+ */
173
+ resumeParked(signal?: AbortSignal): Promise<readonly ResumeAttempt[]>;
174
+ /**
175
+ * Record or clear one session's goal opt-out.
176
+ * @param sessionId - the parked session to change.
177
+ * @param rearmGoal - whether the clean resume path may re-arm its goal.
178
+ * @returns the copy for whoever asked.
179
+ */
180
+ setRearmGoal(sessionId: SessionId, rearmGoal: boolean): Promise<CommandResult>;
181
+ /**
182
+ * Release one parked session and the registered members of its tree: the
183
+ * counterpart of a press that registered a whole tree.
184
+ * @param sessionId - the session whose tree the user released.
185
+ * @param signal - cancellation for the tree read and each member's load.
186
+ * @returns what happened to the tree, and the copy for whoever asked.
187
+ */
188
+ releaseTree(sessionId: SessionId, signal?: AbortSignal): Promise<ReleaseTreeOutcome>;
189
+ }
190
+ /** What releasing one session's registered tree did. */
191
+ export interface ReleaseTreeOutcome {
192
+ /** How many sessions this release covered: the session plus its registered descendants. */
193
+ readonly members: number;
194
+ /** How many of them are running again. */
195
+ readonly resumed: number;
196
+ /** How many could not be resumed, and why the release did not take them back. */
197
+ readonly refusals: readonly {
198
+ readonly sessionId: SessionId;
199
+ readonly refusal: ResumeRefusal;
200
+ }[];
201
+ /** The copy for whoever pressed the release. */
202
+ readonly answer: CommandResult;
203
+ }
204
+ /**
205
+ * How one tree-wide release answers the person who pressed it. One release, one
206
+ * sentence about all of it: what came back, and — by name, because those rows
207
+ * are what the morning list is for — what did not.
208
+ * @param released - the sessions this release covered, in release order.
209
+ * @returns the result text, e.g. `pause resumed 2 sessions from where they stopped; "child" did not pause completely`.
210
+ */
211
+ export declare function summarizeTreeRelease(released: readonly ResumeAttempt[]): string;
212
+ /**
213
+ * Build the clean resume path.
214
+ * @param ctx - host context carrying the agent store, the session store, and the goal service when one is mounted.
215
+ * @param gate - the pause gate the resume releases.
216
+ * @param registry - the durable list this path reads and forgets from.
217
+ * @param options - the route knowledge the wake content depends on.
218
+ * @param deps - the control-owned release order and the adopted-pause fact.
219
+ * @returns the path the session control exposes.
220
+ */
221
+ export declare function installResumePath(ctx: Context, gate: PauseGate, registry: ParkRegistry, options: ResumeOptions, deps: ResumeDeps): ResumePath;