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.
- package/CHANGELOG.md +41 -0
- package/DEVELOPMENT.md +55 -0
- package/LICENSE +21 -0
- package/README.md +130 -2
- package/README.zh.md +91 -0
- package/REHEARSAL.md +90 -0
- package/cordis.patch.yml +3 -0
- package/docs/images/pause-controls.webp +0 -0
- package/icon.svg +5 -0
- package/lib/client.js +2299 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +2975 -0
- package/lib/index.js.map +1 -0
- package/lib/types/client/burst.d.ts +253 -0
- package/lib/types/client/control.d.ts +232 -0
- package/lib/types/client/global.d.ts +325 -0
- package/lib/types/client/icons.d.ts +24 -0
- package/lib/types/client/index.d.ts +77 -0
- package/lib/types/client/locales.d.ts +69 -0
- package/lib/types/client/pill.d.ts +49 -0
- package/lib/types/client/view.d.ts +137 -0
- package/lib/types/coldlog.d.ts +111 -0
- package/lib/types/composition.d.ts +94 -0
- package/lib/types/control.d.ts +114 -0
- package/lib/types/gate.d.ts +110 -0
- package/lib/types/global.d.ts +101 -0
- package/lib/types/history.d.ts +47 -0
- package/lib/types/index.d.ts +64 -0
- package/lib/types/park.d.ts +50 -0
- package/lib/types/registry.d.ts +117 -0
- package/lib/types/resume.d.ts +221 -0
- package/lib/types/shared.d.ts +324 -0
- package/lib/types/tree.d.ts +71 -0
- package/lib/types/triage.d.ts +121 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +148 -4
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The identities both halves of dsh-pause-session name, the status encodings they
|
|
3
|
+
* share, and the one spelling a host log line gives a caught value.
|
|
4
|
+
*
|
|
5
|
+
* The browser bundle may value-import only the shell's baseline module table,
|
|
6
|
+
* so this module imports nothing: the client half reads command names and the
|
|
7
|
+
* decode functions from it directly, and the host half derives the branded
|
|
8
|
+
* identities from the same strings.
|
|
9
|
+
*
|
|
10
|
+
* A third-party plugin's only live channel to the browser is the command
|
|
11
|
+
* registry — it can add neither a `ctx.remote` namespace nor a forwarded event,
|
|
12
|
+
* both of which are compiled into the harness's own API assembly. A command
|
|
13
|
+
* descriptor's only free-form field is its `description`, and a command
|
|
14
|
+
* result's only free-form field is its `text`, so the park state travels as a
|
|
15
|
+
* prefix plus `;`-separated fields on one of those. The text stays
|
|
16
|
+
* human-readable: the same words are what the slash-command menu shows.
|
|
17
|
+
*
|
|
18
|
+
* Every value inside a field is escaped, so a decoded name is the exact name
|
|
19
|
+
* that was encoded. Session ids, tool names, and call ids are the host's own
|
|
20
|
+
* data and may contain the `;`, `,`, `/`, or newline a field is separated by; a
|
|
21
|
+
* folded spelling would decode as a different name — a different row, looked up
|
|
22
|
+
* again.
|
|
23
|
+
* @module dsh-pause-session/shared
|
|
24
|
+
*/
|
|
25
|
+
/** Command that pauses the receiving session before its next model request. */
|
|
26
|
+
export declare const PAUSE_COMMAND = "pause";
|
|
27
|
+
/** Command that resumes the receiving session; registered only while that session is paused. */
|
|
28
|
+
export declare const RESUME_COMMAND = "pause-resume";
|
|
29
|
+
/** Command that resumes every parked session the registry remembers. */
|
|
30
|
+
export declare const RESUME_ALL_COMMAND = "pause-resume-all";
|
|
31
|
+
/** Command that registers and parks every running session tree in one action. */
|
|
32
|
+
export declare const PAUSE_ALL_COMMAND = "pause-all";
|
|
33
|
+
/** Command that reports the whole-app park state; registered globally, always. */
|
|
34
|
+
export declare const STATE_ALL_COMMAND = "pause-state-all";
|
|
35
|
+
/** Command that reports the receiving session's park state; registered only while it is paused. */
|
|
36
|
+
export declare const STATUS_COMMAND = "pause-state";
|
|
37
|
+
/** Command that turns the receiving session's own goal re-arm on or off; registered only while it is paused. */
|
|
38
|
+
export declare const GOAL_COMMAND = "pause-goal";
|
|
39
|
+
/** Command that reports every session that did not stop cleanly. */
|
|
40
|
+
export declare const TRIAGE_COMMAND = "pause-triage";
|
|
41
|
+
/** Command that resumes one session from the decision list exactly as the clean path would. */
|
|
42
|
+
export declare const TRIAGE_CONTINUE_COMMAND = "pause-triage-continue";
|
|
43
|
+
/** Command that resumes one session from the decision list with the unknown-outcome note. */
|
|
44
|
+
export declare const TRIAGE_NOTE_COMMAND = "pause-triage-note";
|
|
45
|
+
/** Command that opens one session from the decision list without spending a request. */
|
|
46
|
+
export declare const TRIAGE_REVIEW_COMMAND = "pause-triage-review";
|
|
47
|
+
/** Command that leaves one session from the decision list exactly as it is. */
|
|
48
|
+
export declare const TRIAGE_LEAVE_COMMAND = "pause-triage-leave";
|
|
49
|
+
/** Command that turns one listed session's goal re-arm on or off. */
|
|
50
|
+
export declare const TRIAGE_GOAL_COMMAND = "pause-triage-goal";
|
|
51
|
+
/** Stable definition id of the pause command, matched by identity rather than by copy. */
|
|
52
|
+
export declare const PAUSE_DEFINITION_ID = "dsh-pause-session/pause";
|
|
53
|
+
/** Stable definition id of the resume command: the host's own "this session is paused" fact. */
|
|
54
|
+
export declare const RESUME_DEFINITION_ID = "dsh-pause-session/resume";
|
|
55
|
+
/** Stable definition id of the global resume command, matched by identity rather than by copy. */
|
|
56
|
+
export declare const RESUME_ALL_DEFINITION_ID = "dsh-pause-session/resume-all";
|
|
57
|
+
/** Stable definition id of the whole-app pause command. */
|
|
58
|
+
export declare const PAUSE_ALL_DEFINITION_ID = "dsh-pause-session/pause-all";
|
|
59
|
+
/** Stable definition id of the whole-app status read. */
|
|
60
|
+
export declare const STATE_ALL_DEFINITION_ID = "dsh-pause-session/state-all";
|
|
61
|
+
/** Stable definition id of the status read, matched by identity rather than by copy. */
|
|
62
|
+
export declare const STATUS_DEFINITION_ID = "dsh-pause-session/status";
|
|
63
|
+
/** Stable definition id of the paused session's own goal re-arm toggle. */
|
|
64
|
+
export declare const GOAL_DEFINITION_ID = "dsh-pause-session/goal";
|
|
65
|
+
/** Stable definition id of the decision-list read. */
|
|
66
|
+
export declare const TRIAGE_DEFINITION_ID = "dsh-pause-session/triage";
|
|
67
|
+
/** Stable definition id of the decision-list "continue" verb. */
|
|
68
|
+
export declare const TRIAGE_CONTINUE_DEFINITION_ID = "dsh-pause-session/triage-continue";
|
|
69
|
+
/** Stable definition id of the decision-list "continue with the unknown-outcome note" verb. */
|
|
70
|
+
export declare const TRIAGE_NOTE_DEFINITION_ID = "dsh-pause-session/triage-note";
|
|
71
|
+
/** Stable definition id of the decision-list "open without activating" verb. */
|
|
72
|
+
export declare const TRIAGE_REVIEW_DEFINITION_ID = "dsh-pause-session/triage-review";
|
|
73
|
+
/** Stable definition id of the decision-list "leave it alone today" verb. */
|
|
74
|
+
export declare const TRIAGE_LEAVE_DEFINITION_ID = "dsh-pause-session/triage-leave";
|
|
75
|
+
/** Stable definition id of the decision-list goal re-arm toggle. */
|
|
76
|
+
export declare const TRIAGE_GOAL_DEFINITION_ID = "dsh-pause-session/triage-goal";
|
|
77
|
+
/** First token of every encoded status, so a descriptor is never parsed by accident. */
|
|
78
|
+
export declare const STATUS_PREFIX = "pause: ";
|
|
79
|
+
/**
|
|
80
|
+
* One log line's text for a caught value.
|
|
81
|
+
* @param error - the caught value.
|
|
82
|
+
* @returns the error's message, or the value's own spelling.
|
|
83
|
+
*/
|
|
84
|
+
export declare function describeError(error: unknown): string;
|
|
85
|
+
/**
|
|
86
|
+
* The four park outcomes, listed in the order a park walks them — and the one
|
|
87
|
+
* vocabulary the live status, the durable registry, and the published words all
|
|
88
|
+
* derive from, so they cannot drift apart:
|
|
89
|
+
*
|
|
90
|
+
* - `draining`: paused, and the session is still working — a tool is running, or
|
|
91
|
+
* a turn is between steps.
|
|
92
|
+
* - `parking`: standing still at the park point; the session-level flush has
|
|
93
|
+
* not resolved yet.
|
|
94
|
+
* - `safe`: parked and flushed, so it is safe to walk away. The only clean one.
|
|
95
|
+
* - `flush-failed`: parked, but the flush failed — the durable promise is not
|
|
96
|
+
* kept, and it must never be read as clean.
|
|
97
|
+
*/
|
|
98
|
+
export declare const PARK_PHASES: readonly ["draining", "parking", "safe", "flush-failed"];
|
|
99
|
+
/** One park outcome. */
|
|
100
|
+
export type ParkPhase = (typeof PARK_PHASES)[number];
|
|
101
|
+
/**
|
|
102
|
+
* Fold several records into the one verdict that speaks for all of them: the
|
|
103
|
+
* worst phase any of them reached, and whether every one of them is clean.
|
|
104
|
+
*
|
|
105
|
+
* This is how a session's control answers for its tree. "Safe to close" is a
|
|
106
|
+
* promise about everything the press registered, so it may be said only when
|
|
107
|
+
* every member reached the flushed park point; anything else is reported as the
|
|
108
|
+
* least-clean state in the set, never rounded up to the session's own.
|
|
109
|
+
* @param phases - the durable phases of the records being spoken for.
|
|
110
|
+
* @returns the worst phase, and whether that verdict is the clean one.
|
|
111
|
+
*/
|
|
112
|
+
export declare function foldTreePhases(phases: Iterable<ParkPhase>): {
|
|
113
|
+
phase: ParkPhase;
|
|
114
|
+
safe: boolean;
|
|
115
|
+
};
|
|
116
|
+
/** Everything the browser is told about one paused session. */
|
|
117
|
+
export interface ParkStatus {
|
|
118
|
+
/**
|
|
119
|
+
* The phase of everything that session's press registered — the session and
|
|
120
|
+
* the subagent members under it, folded by {@link foldTreePhases}. A member
|
|
121
|
+
* still draining or stalled holds this at its own phase, because the control
|
|
122
|
+
* that owns the tree may not say "safe to close" while any member of it is
|
|
123
|
+
* not.
|
|
124
|
+
*/
|
|
125
|
+
readonly phase: ParkPhase;
|
|
126
|
+
/** Whether the host commits to "you can close the lid now". */
|
|
127
|
+
readonly safe: boolean;
|
|
128
|
+
/** Tools in flight when the status was published; empty once parked. */
|
|
129
|
+
readonly runningTools: readonly string[];
|
|
130
|
+
/**
|
|
131
|
+
* Whether the resume that takes this pause back may re-open the session's
|
|
132
|
+
* goal — the durable record's own opt-out, which outlives this process. It is
|
|
133
|
+
* absent when this host could not read the record that holds it; a browser
|
|
134
|
+
* that is not told shows no switch rather than a state it would have to
|
|
135
|
+
* guess, and a guess here would tell the user their money is safe when
|
|
136
|
+
* nobody knows whether it is.
|
|
137
|
+
*/
|
|
138
|
+
readonly rearmGoal?: boolean;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Encode one status for a command descriptor.
|
|
142
|
+
* @param status - the state to publish.
|
|
143
|
+
* @returns the descriptor text, e.g. `pause: draining; tools: edit, bash; goal: on`.
|
|
144
|
+
*/
|
|
145
|
+
export declare function encodeParkStatus(status: ParkStatus): string;
|
|
146
|
+
/**
|
|
147
|
+
* Decode a status previously written by {@link encodeParkStatus}.
|
|
148
|
+
* @param text - a command descriptor's description.
|
|
149
|
+
* @returns the status, or `undefined` when this text carries none — a foreign
|
|
150
|
+
* command, or a reading taken before the host published anything.
|
|
151
|
+
*/
|
|
152
|
+
export declare function decodeParkStatus(text: string): ParkStatus | undefined;
|
|
153
|
+
/**
|
|
154
|
+
* First token of every encoded whole-app status. A different prefix from the
|
|
155
|
+
* per-session status on purpose: one decoder must never read the other's text.
|
|
156
|
+
*/
|
|
157
|
+
export declare const GLOBAL_STATUS_PREFIX = "pause all: ";
|
|
158
|
+
/** The whole-app answer to "can I close the lid?". */
|
|
159
|
+
export type GlobalVerdict = 'idle' | 'waiting' | 'safe';
|
|
160
|
+
/** A surface the whole-app report could not read at all. */
|
|
161
|
+
export type GlobalBlindSpot = 'trees' | 'jobs';
|
|
162
|
+
/**
|
|
163
|
+
* Everything the whole-app control publishes about the park as a whole.
|
|
164
|
+
*
|
|
165
|
+
* The counts and the names are one answer, not two: a report that says
|
|
166
|
+
* "3 registered, 1 safe" and then fails to say which two are missing is the
|
|
167
|
+
* kind of silence this control exists to prevent. The verdict is the only
|
|
168
|
+
* summary, and it is derived here so the host and the browser cannot disagree
|
|
169
|
+
* about it.
|
|
170
|
+
*/
|
|
171
|
+
export interface GlobalStatus {
|
|
172
|
+
/** `idle` with nothing registered, `safe` only when every registered session is. */
|
|
173
|
+
readonly verdict: GlobalVerdict;
|
|
174
|
+
/** Sessions this park owns — the durable list plus anything pressed since. */
|
|
175
|
+
readonly registered: number;
|
|
176
|
+
/** How many of them reached the flushed park point. */
|
|
177
|
+
readonly safe: number;
|
|
178
|
+
/**
|
|
179
|
+
* The session this park belongs to — the first registered one this host can
|
|
180
|
+
* hold, whatever phase it reached, so a client can address its reads at the
|
|
181
|
+
* park instead of at whatever session the user happens to be looking at. A
|
|
182
|
+
* park whose every record is unreadable here names the first of those: the
|
|
183
|
+
* name is a fact about the park, and an address that cannot answer is the
|
|
184
|
+
* client's fallback to take.
|
|
185
|
+
*
|
|
186
|
+
* The buckets below name a session only while it has something left to do,
|
|
187
|
+
* and the clean case — every registered session `safe`, which is the ordinary
|
|
188
|
+
* one — leaves all of them empty: without this field a park that finished
|
|
189
|
+
* cleanly names no session at all. `undefined` when the park holds nothing,
|
|
190
|
+
* and absent from a reading written before this field existed; a client must
|
|
191
|
+
* not treat either absence as an address.
|
|
192
|
+
*/
|
|
193
|
+
readonly parkedAt?: string;
|
|
194
|
+
/**
|
|
195
|
+
* Registered sessions still working: a tool is in flight or a turn is between
|
|
196
|
+
* steps. Their park point is announced by the marker commands the park
|
|
197
|
+
* registers, so a reader has nothing to watch here.
|
|
198
|
+
*/
|
|
199
|
+
readonly draining: readonly string[];
|
|
200
|
+
/**
|
|
201
|
+
* How many registered sessions stand at the park point with their flush still
|
|
202
|
+
* pending — the host's `parking` phase. Nothing announces a flush resolving,
|
|
203
|
+
* so this is the one state a reader can only learn by asking again. A count
|
|
204
|
+
* rather than names: it says how long to keep watching, not which transcript
|
|
205
|
+
* a row belongs in, which is what `draining` is for.
|
|
206
|
+
*/
|
|
207
|
+
readonly parking: number;
|
|
208
|
+
/**
|
|
209
|
+
* Registered sessions that will not reach the park point in this process: a
|
|
210
|
+
* flush that failed, a pause adopted from an earlier process, a press whose
|
|
211
|
+
* registry write failed, or a record whose session this host cannot read and
|
|
212
|
+
* therefore did not hold. Named, never folded into the count and forgotten.
|
|
213
|
+
*/
|
|
214
|
+
readonly stalled: readonly string[];
|
|
215
|
+
/** Registered sessions whose tree contains a route a restart cannot resume. */
|
|
216
|
+
readonly unresumable: readonly string[];
|
|
217
|
+
/** Registered sessions whose subagent tree could not be read — unknown, not clean. */
|
|
218
|
+
readonly unreadTrees: readonly string[];
|
|
219
|
+
/** Live background jobs owned by the registered trees; nothing here can stop them. */
|
|
220
|
+
readonly jobs: readonly string[];
|
|
221
|
+
/** Whole surfaces the report could not read, so their emptiness is not a fact. */
|
|
222
|
+
readonly blind: readonly GlobalBlindSpot[];
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Encode one whole-app status for a command result.
|
|
226
|
+
* @param status - the state to publish.
|
|
227
|
+
* @returns the result text, e.g.
|
|
228
|
+
* `pause all: waiting; registered: 3; safe: 1; parked-at: overnight; draining: overnight; parking: 1; stalled: -; unresumable: -; unread-trees: -; jobs: bash-1; blind: -`.
|
|
229
|
+
*/
|
|
230
|
+
export declare function encodeGlobalStatus(status: GlobalStatus): string;
|
|
231
|
+
/**
|
|
232
|
+
* Decode a whole-app status previously written by {@link encodeGlobalStatus}.
|
|
233
|
+
* @param text - a command result's text.
|
|
234
|
+
* @returns the status, or `undefined` when this text carries none.
|
|
235
|
+
*/
|
|
236
|
+
export declare function decodeGlobalStatus(text: string): GlobalStatus | undefined;
|
|
237
|
+
/**
|
|
238
|
+
* First token of every encoded decision list. Separate from the per-session and
|
|
239
|
+
* whole-app status prefixes on purpose, for the same reason those two are
|
|
240
|
+
* separate: one decoder must never read another's text.
|
|
241
|
+
*/
|
|
242
|
+
export declare const TRIAGE_PREFIX = "pause triage: ";
|
|
243
|
+
/** How one decision-list row was read out of the session's own stored log. */
|
|
244
|
+
export type TriageReading = 'read' | 'unreadable';
|
|
245
|
+
/**
|
|
246
|
+
* What one stored log says about a tool call whose outcome was never recorded.
|
|
247
|
+
*
|
|
248
|
+
* The call event itself is durable; the harness turns every such call into a
|
|
249
|
+
* synthetic `TOOL_OUTCOME_UNKNOWN` error result when it next reads the log, and
|
|
250
|
+
* this is that same derivation taken without writing anything back. The marker
|
|
251
|
+
* itself is never in the stored log of a session still on the list: the resume
|
|
252
|
+
* that appends it is also the resume that drops the record putting it here.
|
|
253
|
+
*/
|
|
254
|
+
export interface TriageTrace {
|
|
255
|
+
/** The tool's own name, from the call event the model produced. */
|
|
256
|
+
readonly tool: string;
|
|
257
|
+
/** The provider-issued id pairing the call with the result that never arrived. */
|
|
258
|
+
readonly callId: string;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* One session that did not stop cleanly, as the decision list presents it.
|
|
262
|
+
*
|
|
263
|
+
* Every field is read from the session's own log or from the durable park
|
|
264
|
+
* record; nothing here is derived from the fact that the session is merely
|
|
265
|
+
* listed. `reading` is the honesty field: a log this host could not read says
|
|
266
|
+
* `unreadable` and carries no facts, rather than an empty row that would read
|
|
267
|
+
* as "no traces".
|
|
268
|
+
*/
|
|
269
|
+
export interface TriageRow {
|
|
270
|
+
/** The parked session. */
|
|
271
|
+
readonly sessionId: string;
|
|
272
|
+
/** The durable park outcome; never `safe`, which is the clean path's business. */
|
|
273
|
+
readonly phase: Exclude<ParkPhase, 'safe'>;
|
|
274
|
+
/** When that outcome was last written. */
|
|
275
|
+
readonly updatedAt: number;
|
|
276
|
+
/** Whether the facts below came from the log. */
|
|
277
|
+
readonly reading: TriageReading;
|
|
278
|
+
/** What the stored log's last event was, with the step it belongs to when it has one. */
|
|
279
|
+
readonly lastEvent?: string;
|
|
280
|
+
/** The turn and step that last event belongs to. */
|
|
281
|
+
readonly turn?: number;
|
|
282
|
+
readonly step?: number;
|
|
283
|
+
/** Tools whose call event is durable and whose result is not — the unknown outcomes. */
|
|
284
|
+
readonly traces: readonly TriageTrace[];
|
|
285
|
+
/** Whether the stored log ends owing the model an answer. */
|
|
286
|
+
readonly owed: boolean;
|
|
287
|
+
/**
|
|
288
|
+
* Whether resuming this session may re-open its goal. Re-arming is what makes
|
|
289
|
+
* a resumed goal spend its owner's rounds, so it is a per-session choice the
|
|
290
|
+
* row shows and the list can flip.
|
|
291
|
+
*/
|
|
292
|
+
readonly rearmGoal: boolean;
|
|
293
|
+
/**
|
|
294
|
+
* Whether the host could hand this session its owed request at all: a log it
|
|
295
|
+
* could not read, or one whose last request recorded no route, cannot be
|
|
296
|
+
* woken — which is a fact about the entry, not a refusal of the user's choice.
|
|
297
|
+
*/
|
|
298
|
+
readonly wakeable: boolean;
|
|
299
|
+
}
|
|
300
|
+
/** The decision list: what did not stop cleanly, and each row's facts. */
|
|
301
|
+
export interface TriageList {
|
|
302
|
+
/** Every listed session, in registry order. */
|
|
303
|
+
readonly rows: readonly TriageRow[];
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* The decisions the list offers for one row. The first four carry the row out;
|
|
307
|
+
* `goal` changes what the next resume may spend without touching the park
|
|
308
|
+
* itself.
|
|
309
|
+
*/
|
|
310
|
+
export declare const TRIAGE_ACTIONS: readonly ["continue", "note", "review", "leave", "goal"];
|
|
311
|
+
/** One decision the list offers. */
|
|
312
|
+
export type TriageAction = (typeof TRIAGE_ACTIONS)[number];
|
|
313
|
+
/**
|
|
314
|
+
* Encode one decision list for a command result.
|
|
315
|
+
* @param list - the rows to publish.
|
|
316
|
+
* @returns the result text, e.g. `pause triage: 1; row: overnight; phase: draining; stopped: tool/call/turn 1 step 1; tools: gated; wake: yes`.
|
|
317
|
+
*/
|
|
318
|
+
export declare function encodeTriageList(list: TriageList): string;
|
|
319
|
+
/**
|
|
320
|
+
* Decode a decision list previously written by {@link encodeTriageList}.
|
|
321
|
+
* @param text - a command result's text.
|
|
322
|
+
* @returns the list, or `undefined` when this text carries none.
|
|
323
|
+
*/
|
|
324
|
+
export declare function decodeTriageList(text: string): TriageList | undefined;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One session's subagent tree, read from the parent catalogs.
|
|
3
|
+
*
|
|
4
|
+
* "This session's work" includes the subagents it delegated to, nested ones
|
|
5
|
+
* included, so the session-header press and the status the header shows both
|
|
6
|
+
* need the same answer to "which sessions hang under this one".
|
|
7
|
+
* `listDescendants` is the harness's own recursive walk of the parent-owned
|
|
8
|
+
* catalogs, and it is the only source: the tree is read from the parents that
|
|
9
|
+
* record it, never guessed from session ids.
|
|
10
|
+
*
|
|
11
|
+
* A walk is read, not remembered. The tree is a fact that grows — a delegation
|
|
12
|
+
* in flight publishes its child after the parent's catalog was read — so a
|
|
13
|
+
* press walks the tree at press time and a status read walks it at read time.
|
|
14
|
+
* `@module dsh-pause-session/tree`
|
|
15
|
+
*/
|
|
16
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
17
|
+
import type { SessionId } from '@deepseek-ai/dsh-session';
|
|
18
|
+
/** One session a walk found under another, with the catalog's own mode for it. */
|
|
19
|
+
export interface TreeMember {
|
|
20
|
+
readonly id: SessionId;
|
|
21
|
+
/**
|
|
22
|
+
* The catalog's durable mode for this child. `external` is a child with no
|
|
23
|
+
* local session to park, and `unsupported` is a mode this build cannot read;
|
|
24
|
+
* the other two are the harness's own split between a route a restart can
|
|
25
|
+
* resume (`continuable`) and one it cannot.
|
|
26
|
+
*/
|
|
27
|
+
readonly mode: 'one-shot' | 'external' | 'continuable' | 'unsupported';
|
|
28
|
+
}
|
|
29
|
+
/** One branch a walk reached and could not read. */
|
|
30
|
+
export interface UnreadBranch {
|
|
31
|
+
readonly id: SessionId;
|
|
32
|
+
/**
|
|
33
|
+
* `corrupt` and `unavailable` mean the branch's own catalog was not read, so
|
|
34
|
+
* the members under it are unknown. `unsupported` means the parent's catalog
|
|
35
|
+
* records a mode this build cannot read; that branch was still traversed, and
|
|
36
|
+
* what it holds is known — but no restart can resume through it.
|
|
37
|
+
*/
|
|
38
|
+
readonly reason: 'corrupt' | 'unsupported' | 'unavailable';
|
|
39
|
+
}
|
|
40
|
+
/** What one session's tree walk found. */
|
|
41
|
+
export interface TreeWalk {
|
|
42
|
+
/**
|
|
43
|
+
* Catalog descendants in pre-order, direct children first and each child's
|
|
44
|
+
* own children after it. A missing subagent service leaves this empty.
|
|
45
|
+
*/
|
|
46
|
+
readonly members: readonly TreeMember[];
|
|
47
|
+
/**
|
|
48
|
+
* Branches the walk reached and could not fully read. A branch named here may
|
|
49
|
+
* hold members nobody can see, so it is never read as "no members".
|
|
50
|
+
*/
|
|
51
|
+
readonly unread: readonly UnreadBranch[];
|
|
52
|
+
/**
|
|
53
|
+
* Whether the walk itself failed, so even the branches are unknown. Named
|
|
54
|
+
* separately from {@link unread}, which lists the branches of a walk that ran.
|
|
55
|
+
*/
|
|
56
|
+
readonly unreadWhole: boolean;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Read the subagent tree under one session.
|
|
60
|
+
*
|
|
61
|
+
* A failure to read a branch is reported as unread rather than as an empty
|
|
62
|
+
* tree: the difference is what keeps a press from claiming it registered a tree
|
|
63
|
+
* it never saw, and keeps a status answer from calling itself safe behind an
|
|
64
|
+
* unknown branch.
|
|
65
|
+
* @param ctx - host context carrying the optional subagent service.
|
|
66
|
+
* @param rootSessionId - the session whose descendants are requested.
|
|
67
|
+
* @param signal - cancellation for the catalog walk.
|
|
68
|
+
* @returns the descendants found and what of the walk could not be read.
|
|
69
|
+
* @throws the cancellation reason when `signal` aborts the walk.
|
|
70
|
+
*/
|
|
71
|
+
export declare function walkDescendants(ctx: Context, rootSessionId: SessionId, signal?: AbortSignal): Promise<TreeWalk>;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The morning decision list: every session that did not stop cleanly, the facts
|
|
3
|
+
* its own log carries about where it stopped, and the listed verbs the user can
|
|
4
|
+
* take on it.
|
|
5
|
+
*
|
|
6
|
+
* A session gets here by NOT being on the clean path. A record whose phase is
|
|
7
|
+
* `safe` is woken silently by `./resume.ts` and never appears here; the other
|
|
8
|
+
* three phases describe work nobody can vouch for, and guessing on them would
|
|
9
|
+
* spend the owner's money on a guess. This module is the other half of that
|
|
10
|
+
* rule, not a second copy of it: the reading is taken from the session's own
|
|
11
|
+
* stored log through a read handle that claims no ownership and writes nothing,
|
|
12
|
+
* so asking what happened cannot itself change what happened.
|
|
13
|
+
*
|
|
14
|
+
* WHAT ONE READ COSTS. The list is read again on every command-registry change
|
|
15
|
+
* while the panel is open, and what it publishes is about the end of a log that
|
|
16
|
+
* only grows, so `./coldlog.ts` bounds each row's read to that end. A row whose
|
|
17
|
+
* facts the bound cannot hold reports itself unreadable rather than publishing
|
|
18
|
+
* a fragment.
|
|
19
|
+
*
|
|
20
|
+
* WHAT A ROW REPORTS. "Where it stopped" is the last event of the stored log
|
|
21
|
+
* with the turn and step it belongs to. "Which tool was in flight" is the
|
|
22
|
+
* `tool/call` events that no durable `tool/result` answers — a call event is
|
|
23
|
+
* only written once the loop reached the dispatch, so an unanswered one is
|
|
24
|
+
* exactly a tool the real world ran and the log never heard back from. The
|
|
25
|
+
* harness turns each of those into a synthetic `TOOL_OUTCOME_UNKNOWN` error
|
|
26
|
+
* result when it next reads the log; this module derives the same answer from
|
|
27
|
+
* the stored events instead of writing it back. Nothing here is inferred from
|
|
28
|
+
* the fact that the session is listed.
|
|
29
|
+
*
|
|
30
|
+
* WHAT THE ROW PROMISES. `wake` says the host can hand this session the request
|
|
31
|
+
* it owes, and the wake that keeps that promise is `./resume.ts`'s. Both read
|
|
32
|
+
* one rule from `./history.ts` over the same derivation the loop reads, so a
|
|
33
|
+
* promise this list publishes is a promise that wake keeps. When the log cannot
|
|
34
|
+
* be folded into that derivation, the promise is withheld and the reading is
|
|
35
|
+
* reported; a withheld promise costs a user nothing, a broken one spends their
|
|
36
|
+
* money.
|
|
37
|
+
*
|
|
38
|
+
* WHO MAY DECIDE. A decision names its target as command input, and the command
|
|
39
|
+
* channel carries no origin of its own, so this list acts only on rows its most
|
|
40
|
+
* recent read published to the calling session: the caller's own read is what
|
|
41
|
+
* makes a target actionable. Anything else is refused, not looked up.
|
|
42
|
+
*
|
|
43
|
+
* TWO OF THE FIVE VERBS PUT THE SESSION BACK ON THE CLEAN PATH. Continue and
|
|
44
|
+
* continue-with-the-note go through `ResumePath.decideUnclean`, which activates
|
|
45
|
+
* the session, wakes it and drops the durable record before the gate opens.
|
|
46
|
+
*
|
|
47
|
+
* THE OTHER THREE TOUCH NOTHING. Leave writes nothing at all: the record stays,
|
|
48
|
+
* the session stays held, and the row is still on tomorrow's list. Review
|
|
49
|
+
* answers without activating anything or writing anything — opening a session
|
|
50
|
+
* to read it is the user's own action in their session history, and starting an
|
|
51
|
+
* agent on their behalf is precisely what they declined. Goal flips the row's
|
|
52
|
+
* own re-arm opt-out: it is the user path for the one thing a resume can spend
|
|
53
|
+
* without the user watching it, and it takes effect on whatever resume comes
|
|
54
|
+
* next. All five carry the same binding — the row must be one this caller was
|
|
55
|
+
* shown — because each changes, or declines to change, durable state of a
|
|
56
|
+
* parked session.
|
|
57
|
+
* @module dsh-pause-session/triage
|
|
58
|
+
*/
|
|
59
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
60
|
+
import type { SessionId } from '@deepseek-ai/dsh-session';
|
|
61
|
+
import type { CommandResult } from '@deepseek-ai/dsh-commands';
|
|
62
|
+
import type { ParkRegistry } from './registry.js';
|
|
63
|
+
import type { ResumePath } from './resume.js';
|
|
64
|
+
import type { TriageAction, TriageList } from './shared.js';
|
|
65
|
+
/** Result copy for a decision the list itself could not carry out. */
|
|
66
|
+
export declare const TRIAGE_FAILED_TEXT = "pause could not carry out that decision; the session is exactly as it was.";
|
|
67
|
+
/** Result copy for leaving one listed session alone. */
|
|
68
|
+
export declare const TRIAGE_LEFT_TEXT = "pause left this session paused; it is still on the list.";
|
|
69
|
+
/** Result copy for a decision aimed at a session that is not on the list. */
|
|
70
|
+
export declare const TRIAGE_NOT_LISTED_TEXT = "pause has no unfinished pause for this session.";
|
|
71
|
+
/**
|
|
72
|
+
* Result copy for a decision aimed at a row the calling session was not shown.
|
|
73
|
+
* The list is the only thing that legitimizes a target, so a target nobody read
|
|
74
|
+
* is refused rather than acted on.
|
|
75
|
+
*/
|
|
76
|
+
export declare const TRIAGE_UNSHOWN_TEXT: string;
|
|
77
|
+
/**
|
|
78
|
+
* Model-facing text that goes with a wake when the user chooses to continue
|
|
79
|
+
* with a note.
|
|
80
|
+
*
|
|
81
|
+
* It is written the way the harness writes its own recovery text: the same two
|
|
82
|
+
* facts the synthetic tool result states (the call's outcome was never recorded;
|
|
83
|
+
* verify before retrying anything with side effects), in the same voice, with no
|
|
84
|
+
* mention of the stop mechanism. The harness's own version lives in the tool
|
|
85
|
+
* result for that call, which is why this one does not repeat the call's name —
|
|
86
|
+
* it warns about the step as a whole, and the specific result sits directly
|
|
87
|
+
* above it in the history.
|
|
88
|
+
*/
|
|
89
|
+
export declare const UNKNOWN_OUTCOME_NOTE: string;
|
|
90
|
+
/** What mounting the decision list hands back. */
|
|
91
|
+
export interface TriageListService {
|
|
92
|
+
/**
|
|
93
|
+
* Read the list for one calling session, and record the rows it was shown.
|
|
94
|
+
* @param caller - the session the read was addressed to.
|
|
95
|
+
* @param signal - cancellation for the stored-log reads.
|
|
96
|
+
* @returns every session that did not stop cleanly, with the facts its own log carries.
|
|
97
|
+
*/
|
|
98
|
+
read(caller: SessionId, signal?: AbortSignal): Promise<TriageList>;
|
|
99
|
+
/**
|
|
100
|
+
* Carry out one decision on one listed session, for the caller that read it.
|
|
101
|
+
* @param caller - the session the decision was addressed to.
|
|
102
|
+
* @param sessionId - the listed session to act on.
|
|
103
|
+
* @param action - which of the listed decisions was taken.
|
|
104
|
+
* @param signal - cancellation for the cold load and setup.
|
|
105
|
+
* @returns the outcome for whoever asked.
|
|
106
|
+
*/
|
|
107
|
+
decide(caller: SessionId, sessionId: SessionId, action: TriageAction, signal?: AbortSignal): Promise<CommandResult>;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Mount the decision list over the durable registry and the clean resume path.
|
|
111
|
+
*
|
|
112
|
+
* The list is the registry's own complement: it asks for every record whose
|
|
113
|
+
* phase is not `safe`, so a session that cleaned up is off the list by the same
|
|
114
|
+
* fact that puts it on the silent path, and nothing has to be reconciled.
|
|
115
|
+
* @param ctx - host context carrying the optional persistence service.
|
|
116
|
+
* @param registry - the durable list of park outcomes.
|
|
117
|
+
* @param resumePath - the path all three resuming decisions go through.
|
|
118
|
+
* @param windowEvents - how many events of each stored log one read may fold.
|
|
119
|
+
* @returns the list read and the decision verbs.
|
|
120
|
+
*/
|
|
121
|
+
export declare function mountTriageList(ctx: Context, registry: ParkRegistry, resumePath: ResumePath, windowEvents?: number): TriageListService;
|
package/locale/en.json
ADDED
package/locale/zh.json
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"title": "\u6682\u505c\u4f1a\u8bdd",
|
|
4
|
+
"description": "\u5728\u5b89\u5168\u70b9\u6682\u505c\u6240\u6709\u8fd0\u884c\u4e2d\u7684\u4f1a\u8bdd\u53ca\u5176\u5b50\u4ee3\u7406\uff0c\u4e4b\u540e\u518d\u4ece\u4e2d\u65ad\u5904\u6062\u590d\uff0c\u4e0d\u4e22\u5931\u6b63\u5728\u6267\u884c\u7684\u5de5\u4f5c\u3002"
|
|
5
|
+
}
|
|
6
|
+
}
|