dsh-pause-session 0.0.0-stage → 0.2.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 +79 -0
- package/DEVELOPMENT.md +78 -0
- package/LICENSE +21 -0
- package/README.md +140 -2
- package/README.zh.md +101 -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 +2024 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +2996 -0
- package/lib/index.js.map +1 -0
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +339 -0
- package/lib/typert.remote-client.d.ts +38 -0
- package/lib/typert.remote-client.d.ts.map +1 -0
- package/lib/typert.remote-client.js +244 -0
- package/lib/types/client/control.d.ts +99 -0
- package/lib/types/client/global.d.ts +125 -0
- package/lib/types/client/icons.d.ts +24 -0
- package/lib/types/client/index.d.ts +78 -0
- package/lib/types/client/locales.d.ts +67 -0
- package/lib/types/client/pill.d.ts +49 -0
- package/lib/types/client/remote.d.ts +71 -0
- package/lib/types/client/view.d.ts +151 -0
- package/lib/types/coldlog.d.ts +111 -0
- package/lib/types/composition.d.ts +94 -0
- package/lib/types/control.d.ts +95 -0
- package/lib/types/gate.d.ts +110 -0
- package/lib/types/global.d.ts +103 -0
- package/lib/types/history.d.ts +47 -0
- package/lib/types/index.d.ts +64 -0
- package/lib/types/park-state.d.ts +51 -0
- package/lib/types/park.d.ts +50 -0
- package/lib/types/registry.d.ts +117 -0
- package/lib/types/release-order.d.ts +21 -0
- package/lib/types/remote-adapter.d.ts +22 -0
- package/lib/types/remote.d.ts +158 -0
- package/lib/types/resume-activation.d.ts +27 -0
- package/lib/types/resume-text.d.ts +67 -0
- package/lib/types/resume.d.ts +126 -0
- package/lib/types/shared.d.ts +221 -0
- package/lib/types/snapshot.d.ts +29 -0
- package/lib/types/tree.d.ts +71 -0
- package/lib/types/triage.d.ts +120 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +166 -3
package/lib/client.js
ADDED
|
@@ -0,0 +1,2024 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "dsh-pause-session",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
|
+
let react = require("react");
|
|
9
|
+
let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
10
|
+
//#region lib/types/client/control.js
|
|
11
|
+
/**
|
|
12
|
+
* Browser-side reading and driving of the host's park state for one session.
|
|
13
|
+
*
|
|
14
|
+
* The browser reads the native `pauseSession` stream; actions travel through
|
|
15
|
+
* the same Remote namespace. No slash command is involved. The stream is
|
|
16
|
+
* host-authoritative, so this module never derives a state from its own press.
|
|
17
|
+
* The snapshot also carries the record's goal opt-out, so the switch beside the
|
|
18
|
+
* pause button can show it without a second host round-trip.
|
|
19
|
+
*
|
|
20
|
+
* The stream is the change feed. A pushed snapshot triggers one cached read per
|
|
21
|
+
* shown header; a press or goal switch reads the host's answer once after the
|
|
22
|
+
* action.
|
|
23
|
+
* @module dsh-pause-session/client/control
|
|
24
|
+
*/
|
|
25
|
+
const INITIAL$1 = { bySession: {} };
|
|
26
|
+
/** Owns the published reading per session; nothing else writes that state. */
|
|
27
|
+
var PauseControl = class {
|
|
28
|
+
transport;
|
|
29
|
+
lifetime;
|
|
30
|
+
/** State source the Session-header contribution binds its selector hook to. */
|
|
31
|
+
store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(INITIAL$1);
|
|
32
|
+
/** Sessions this control has shown; a pushed snapshot applies to every one. */
|
|
33
|
+
shown = /* @__PURE__ */ new Set();
|
|
34
|
+
/** Highest read sequence requested per session: an answer older than it is dropped. */
|
|
35
|
+
latest = /* @__PURE__ */ new Map();
|
|
36
|
+
reads = 0;
|
|
37
|
+
/**
|
|
38
|
+
* @param transport - the native namespace source and actions.
|
|
39
|
+
* @param lifetime - aborts in-flight reads when the plugin unloads.
|
|
40
|
+
*/
|
|
41
|
+
constructor(transport, lifetime) {
|
|
42
|
+
this.transport = transport;
|
|
43
|
+
this.lifetime = lifetime;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Read the host's state for one session.
|
|
47
|
+
* @param sessionId - session whose control was rendered.
|
|
48
|
+
* @returns after this read's answer is published or superseded by a newer one.
|
|
49
|
+
*/
|
|
50
|
+
async refresh(sessionId) {
|
|
51
|
+
await this.readOne(sessionId);
|
|
52
|
+
}
|
|
53
|
+
/** Apply one pushed snapshot without spending a read per shown header. */
|
|
54
|
+
apply(snapshot) {
|
|
55
|
+
for (const sessionId of this.shown) {
|
|
56
|
+
if (snapshot === void 0) {
|
|
57
|
+
this.publish(sessionId, {
|
|
58
|
+
phase: "unavailable",
|
|
59
|
+
runningTools: []
|
|
60
|
+
});
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const status = snapshot.sessions[String(sessionId)];
|
|
64
|
+
this.publish(sessionId, status === void 0 ? {
|
|
65
|
+
phase: "active",
|
|
66
|
+
runningTools: []
|
|
67
|
+
} : {
|
|
68
|
+
phase: status.phase,
|
|
69
|
+
runningTools: status.runningTools,
|
|
70
|
+
...status.rearmGoal === void 0 ? {} : { rearmGoal: status.rearmGoal }
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** A new pushed snapshot may have moved every header; read them once. */
|
|
75
|
+
refreshAll() {
|
|
76
|
+
if (this.shown.size === 0 || this.lifetime.aborted) return;
|
|
77
|
+
this.readAll();
|
|
78
|
+
}
|
|
79
|
+
async readAll() {
|
|
80
|
+
if (this.lifetime.aborted) return;
|
|
81
|
+
for (const sessionId of [...this.shown]) await this.readOne(sessionId);
|
|
82
|
+
}
|
|
83
|
+
/** One session's read, published unless a newer read of that session supersedes it. */
|
|
84
|
+
async readOne(sessionId) {
|
|
85
|
+
this.shown.add(sessionId);
|
|
86
|
+
const sequence = ++this.reads;
|
|
87
|
+
this.latest.set(sessionId, sequence);
|
|
88
|
+
const reading = await this.read(sessionId);
|
|
89
|
+
if (this.latest.get(sessionId) !== sequence) return;
|
|
90
|
+
this.publish(sessionId, reading);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Press the control: pause an active session, or take back a pause that is
|
|
94
|
+
* still on its way in (or already settled). The phase shown afterwards is the
|
|
95
|
+
* host's answer, never an assumed flip.
|
|
96
|
+
* @param sessionId - session whose control was pressed.
|
|
97
|
+
* @returns after the control re-reads the host.
|
|
98
|
+
*/
|
|
99
|
+
async toggle(sessionId) {
|
|
100
|
+
const current = this.store.getSnapshot().bySession[String(sessionId)]?.phase;
|
|
101
|
+
const action = current === void 0 || current === "active" ? "pause" : "resume";
|
|
102
|
+
if (!(await this.transport.act({
|
|
103
|
+
action,
|
|
104
|
+
sessionId: String(sessionId)
|
|
105
|
+
}, this.lifetime)).ok) {
|
|
106
|
+
this.publish(sessionId, {
|
|
107
|
+
phase: "unavailable",
|
|
108
|
+
runningTools: []
|
|
109
|
+
});
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
await this.refresh(sessionId);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Flip this session's goal opt-out. The verb belongs to the session it
|
|
116
|
+
* changes; the switch shows the host's next answer, never a local flip.
|
|
117
|
+
* @param sessionId - session whose switch was pressed.
|
|
118
|
+
* @returns after the control re-reads the host.
|
|
119
|
+
*/
|
|
120
|
+
async toggleGoal(sessionId) {
|
|
121
|
+
if (!(await this.transport.act({
|
|
122
|
+
action: "goal",
|
|
123
|
+
sessionId: String(sessionId)
|
|
124
|
+
}, this.lifetime)).ok) {
|
|
125
|
+
this.publish(sessionId, {
|
|
126
|
+
phase: "unavailable",
|
|
127
|
+
runningTools: []
|
|
128
|
+
});
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
await this.refresh(sessionId);
|
|
132
|
+
}
|
|
133
|
+
/** Ask the native stream what this session's park state is. */
|
|
134
|
+
async read(sessionId) {
|
|
135
|
+
const snapshot = await this.transport.source.read(this.lifetime);
|
|
136
|
+
if (snapshot === void 0) return {
|
|
137
|
+
phase: "unavailable",
|
|
138
|
+
runningTools: []
|
|
139
|
+
};
|
|
140
|
+
const status = snapshot.sessions[String(sessionId)];
|
|
141
|
+
if (status === void 0) return {
|
|
142
|
+
phase: "active",
|
|
143
|
+
runningTools: []
|
|
144
|
+
};
|
|
145
|
+
return {
|
|
146
|
+
phase: status.phase,
|
|
147
|
+
runningTools: status.runningTools,
|
|
148
|
+
...status.rearmGoal === void 0 ? {} : { rearmGoal: status.rearmGoal }
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
publish(sessionId, reading) {
|
|
152
|
+
this.store.update((state) => {
|
|
153
|
+
const previous = state.bySession[String(sessionId)];
|
|
154
|
+
if (previous !== void 0 && previous.phase === reading.phase && previous.rearmGoal === reading.rearmGoal && previous.runningTools.length === reading.runningTools.length && previous.runningTools.every((tool, index) => tool === reading.runningTools[index])) return;
|
|
155
|
+
state.bySession = {
|
|
156
|
+
...state.bySession,
|
|
157
|
+
[String(sessionId)]: reading
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region lib/types/client/view.js
|
|
164
|
+
/**
|
|
165
|
+
* The controls' phase → view mapping.
|
|
166
|
+
*
|
|
167
|
+
* Kept pure functions of the published reading so the rendering decision — what
|
|
168
|
+
* the button says, whether it accepts a press, and which state label is visible
|
|
169
|
+
* — is asserted without a browser renderer. Labels are KEYS, not copy: the
|
|
170
|
+
* visible sentence is localized, and the host's own names join it as data.
|
|
171
|
+
* @module dsh-pause-session/client/view
|
|
172
|
+
*/
|
|
173
|
+
/**
|
|
174
|
+
* Whether the pause control renders on one session at all.
|
|
175
|
+
*
|
|
176
|
+
* The control is the user's button for a session's work, and that work includes
|
|
177
|
+
* the subagents under it — which is why the press covers the tree and why the
|
|
178
|
+
* button does not belong inside the tree. The client can tell: a Session
|
|
179
|
+
* snapshot carries a `subagent` field, the same signal the read-only composer
|
|
180
|
+
* reads. A subagent's service is not the user's to pause: its parent's control
|
|
181
|
+
* already speaks for it, and a second button here would offer to stop "a
|
|
182
|
+
* session" from inside a child.
|
|
183
|
+
* @param subagent - the session snapshot's own subagent fact, absent when unknown.
|
|
184
|
+
* @returns whether this session's header renders the control.
|
|
185
|
+
*/
|
|
186
|
+
function showsPauseControl(subagent) {
|
|
187
|
+
return subagent === null || subagent === void 0;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* One reading's goal opt-out, as the view carries it. Only an answered flag
|
|
191
|
+
* becomes a field: a missing one must stay missing through the mapping, or the
|
|
192
|
+
* renderer would show the product default as if the host had said it.
|
|
193
|
+
* @param reading - the host's answer.
|
|
194
|
+
* @returns the field to spread into the view, empty when the host said nothing.
|
|
195
|
+
*/
|
|
196
|
+
function goalOf(reading) {
|
|
197
|
+
return reading.rearmGoal === void 0 ? {} : { rearmGoal: reading.rearmGoal };
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Map one reading to its view.
|
|
201
|
+
* @param reading - the host-reported reading, or `undefined` before the first answer.
|
|
202
|
+
* @returns the view for that reading.
|
|
203
|
+
*/
|
|
204
|
+
function pauseView(reading, running = true) {
|
|
205
|
+
switch (reading?.phase) {
|
|
206
|
+
case "active": return {
|
|
207
|
+
paused: false,
|
|
208
|
+
enabled: running,
|
|
209
|
+
ariaKey: "pause.aria",
|
|
210
|
+
runningTools: []
|
|
211
|
+
};
|
|
212
|
+
case "draining": return {
|
|
213
|
+
paused: true,
|
|
214
|
+
enabled: true,
|
|
215
|
+
ariaKey: "draining.aria",
|
|
216
|
+
labelKey: "state.draining",
|
|
217
|
+
runningTools: reading.runningTools
|
|
218
|
+
};
|
|
219
|
+
case "parking": return {
|
|
220
|
+
paused: true,
|
|
221
|
+
enabled: true,
|
|
222
|
+
ariaKey: "parking.aria",
|
|
223
|
+
labelKey: "state.parking",
|
|
224
|
+
runningTools: []
|
|
225
|
+
};
|
|
226
|
+
case "safe": return {
|
|
227
|
+
paused: true,
|
|
228
|
+
enabled: true,
|
|
229
|
+
ariaKey: "safe.aria",
|
|
230
|
+
labelKey: "state.safe",
|
|
231
|
+
runningTools: [],
|
|
232
|
+
...goalOf(reading)
|
|
233
|
+
};
|
|
234
|
+
case "flush-failed": return {
|
|
235
|
+
paused: true,
|
|
236
|
+
enabled: true,
|
|
237
|
+
ariaKey: "flushFailed.aria",
|
|
238
|
+
labelKey: "state.flushFailed",
|
|
239
|
+
runningTools: []
|
|
240
|
+
};
|
|
241
|
+
case "unavailable": return {
|
|
242
|
+
paused: false,
|
|
243
|
+
enabled: false,
|
|
244
|
+
ariaKey: "unavailable.aria",
|
|
245
|
+
runningTools: []
|
|
246
|
+
};
|
|
247
|
+
case void 0: return {
|
|
248
|
+
paused: false,
|
|
249
|
+
enabled: false,
|
|
250
|
+
ariaKey: "checking.aria",
|
|
251
|
+
runningTools: []
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/** The four decisions, in the order a user reads them: least to most cautious. */
|
|
256
|
+
const TRIAGE_ACTION_VIEWS = [
|
|
257
|
+
{
|
|
258
|
+
action: "continue",
|
|
259
|
+
labelKey: "triage.continue",
|
|
260
|
+
ariaKey: "triage.continue.aria"
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
action: "note",
|
|
264
|
+
labelKey: "triage.note",
|
|
265
|
+
ariaKey: "triage.note.aria"
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
action: "review",
|
|
269
|
+
labelKey: "triage.review",
|
|
270
|
+
ariaKey: "triage.review.aria"
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
action: "leave",
|
|
274
|
+
labelKey: "triage.leave",
|
|
275
|
+
ariaKey: "triage.leave.aria"
|
|
276
|
+
}
|
|
277
|
+
];
|
|
278
|
+
/**
|
|
279
|
+
* The decisions one row may offer. Continue and note both deliver the owed
|
|
280
|
+
* request, so they are absent when the log is unreadable or the host says it
|
|
281
|
+
* cannot wake the entry; the remaining decisions still give the user a way out.
|
|
282
|
+
* @param row - the rendered row.
|
|
283
|
+
* @returns the actions that can be taken on it.
|
|
284
|
+
*/
|
|
285
|
+
function triageActionsFor(row) {
|
|
286
|
+
return TRIAGE_ACTION_VIEWS.filter((action) => action.action !== "continue" && action.action !== "note" ? true : row.readable && row.wakeable);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* The fifth listed verb, rendered apart from the four decisions: it is a
|
|
290
|
+
* switch on what the NEXT resume may spend, not a way to decide this row.
|
|
291
|
+
*/
|
|
292
|
+
const TRIAGE_GOAL_VIEW = {
|
|
293
|
+
action: "goal",
|
|
294
|
+
labelKey: "triage.goal",
|
|
295
|
+
ariaKey: "triage.goal.aria"
|
|
296
|
+
};
|
|
297
|
+
/** The word each non-clean phase is shown as. */
|
|
298
|
+
const PHASE_KEY = {
|
|
299
|
+
draining: "triage.phase.draining",
|
|
300
|
+
parking: "triage.phase.parking",
|
|
301
|
+
"flush-failed": "triage.phase.flushFailed"
|
|
302
|
+
};
|
|
303
|
+
/**
|
|
304
|
+
* Map one decision-list reading to its view.
|
|
305
|
+
* @param reading - the host-reported list, or `undefined` before the panel asked.
|
|
306
|
+
* @returns the rows as the panel renders them.
|
|
307
|
+
*/
|
|
308
|
+
function triageView(reading) {
|
|
309
|
+
if (reading === void 0) return {
|
|
310
|
+
visible: false,
|
|
311
|
+
unavailable: false,
|
|
312
|
+
rows: []
|
|
313
|
+
};
|
|
314
|
+
if (reading.kind === "unavailable") return {
|
|
315
|
+
visible: true,
|
|
316
|
+
unavailable: true,
|
|
317
|
+
rows: []
|
|
318
|
+
};
|
|
319
|
+
return {
|
|
320
|
+
visible: true,
|
|
321
|
+
unavailable: false,
|
|
322
|
+
rows: reading.rows.map((row) => ({
|
|
323
|
+
sessionId: row.sessionId,
|
|
324
|
+
phaseKey: PHASE_KEY[row.phase],
|
|
325
|
+
...row.lastEvent === void 0 ? {} : { stopped: row.turn === void 0 ? row.lastEvent : `${row.lastEvent} · turn ${String(row.turn)}${row.step === void 0 ? "" : ` step ${String(row.step)}`}` },
|
|
326
|
+
unknownTools: row.traces.map((trace) => trace.tool),
|
|
327
|
+
wakeable: row.wakeable,
|
|
328
|
+
readable: row.reading === "read",
|
|
329
|
+
rearmGoal: row.rearmGoal
|
|
330
|
+
}))
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Map one whole-app reading to its view.
|
|
335
|
+
* @param reading - the host-reported reading, or `undefined` before the first answer.
|
|
336
|
+
* @returns the view for that reading.
|
|
337
|
+
*/
|
|
338
|
+
function globalPauseView(reading, sessions) {
|
|
339
|
+
if (reading === void 0) return {
|
|
340
|
+
visible: false,
|
|
341
|
+
enabled: false,
|
|
342
|
+
ariaKey: "all.checking.aria",
|
|
343
|
+
action: "none",
|
|
344
|
+
detail: "",
|
|
345
|
+
caveats: [],
|
|
346
|
+
unclean: 0
|
|
347
|
+
};
|
|
348
|
+
if (reading.kind === "unavailable") return {
|
|
349
|
+
visible: false,
|
|
350
|
+
enabled: false,
|
|
351
|
+
ariaKey: "unavailable.aria",
|
|
352
|
+
action: "none",
|
|
353
|
+
detail: "",
|
|
354
|
+
caveats: [],
|
|
355
|
+
unclean: 0
|
|
356
|
+
};
|
|
357
|
+
const { status } = reading;
|
|
358
|
+
const caveats = [];
|
|
359
|
+
if (status.blind.includes("jobs")) caveats.push({
|
|
360
|
+
key: "all.caveat.blindJobs",
|
|
361
|
+
names: []
|
|
362
|
+
});
|
|
363
|
+
else if (status.jobs.length > 0) caveats.push({
|
|
364
|
+
key: "all.caveat.jobs",
|
|
365
|
+
names: status.jobs
|
|
366
|
+
});
|
|
367
|
+
if (status.blind.includes("trees")) caveats.push({
|
|
368
|
+
key: "all.caveat.blindTrees",
|
|
369
|
+
names: []
|
|
370
|
+
});
|
|
371
|
+
else if (status.unreadTrees.length > 0) caveats.push({
|
|
372
|
+
key: "all.caveat.unread",
|
|
373
|
+
names: status.unreadTrees
|
|
374
|
+
});
|
|
375
|
+
if (status.unresumable.length > 0) caveats.push({
|
|
376
|
+
key: "all.caveat.unresumable",
|
|
377
|
+
names: status.unresumable
|
|
378
|
+
});
|
|
379
|
+
const verdict = status.verdict;
|
|
380
|
+
if (verdict !== "safe" && status.stalled.length > 0) caveats.push({
|
|
381
|
+
key: "all.caveat.stalled",
|
|
382
|
+
names: status.stalled
|
|
383
|
+
});
|
|
384
|
+
const base = {
|
|
385
|
+
visible: true,
|
|
386
|
+
enabled: true,
|
|
387
|
+
caveats,
|
|
388
|
+
unclean: status.stalled.length
|
|
389
|
+
};
|
|
390
|
+
switch (verdict) {
|
|
391
|
+
case "idle": return {
|
|
392
|
+
...base,
|
|
393
|
+
ariaKey: "all.pause.aria",
|
|
394
|
+
action: "pause-all",
|
|
395
|
+
detail: ""
|
|
396
|
+
};
|
|
397
|
+
case "safe": return {
|
|
398
|
+
...base,
|
|
399
|
+
ariaKey: "all.resume.aria",
|
|
400
|
+
action: "resume-all",
|
|
401
|
+
labelKey: "all.safe",
|
|
402
|
+
detail: `${String(status.safe)}/${String(status.registered)}`
|
|
403
|
+
};
|
|
404
|
+
case "waiting": return status.draining.length > 0 || status.parking > 0 ? {
|
|
405
|
+
...base,
|
|
406
|
+
ariaKey: "all.cancel.aria",
|
|
407
|
+
action: "cancel-all",
|
|
408
|
+
labelKey: "all.finishing",
|
|
409
|
+
detail: `${String(status.safe)}/${String(status.registered)}`,
|
|
410
|
+
running: status.draining.map((id) => {
|
|
411
|
+
const tools = sessions?.[id]?.runningTools ?? [];
|
|
412
|
+
return tools.length === 0 ? id : `${id}: ${tools.join(", ")}`;
|
|
413
|
+
}).join(", ") || void 0
|
|
414
|
+
} : {
|
|
415
|
+
...base,
|
|
416
|
+
enabled: false,
|
|
417
|
+
ariaKey: "all.unclean.aria",
|
|
418
|
+
action: "none",
|
|
419
|
+
labelKey: "all.unclean",
|
|
420
|
+
detail: String(status.stalled.length)
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
//#endregion
|
|
425
|
+
//#region lib/types/client/global.js
|
|
426
|
+
/**
|
|
427
|
+
* Browser-side reading and driving of the host's whole-app park state.
|
|
428
|
+
*
|
|
429
|
+
* The aggregate arrives from the native `pauseSession` stream. The stream is
|
|
430
|
+
* process-wide and writes nothing into any Session; actions travel through the
|
|
431
|
+
* same Remote namespace. A pushed snapshot is applied directly; a settled park
|
|
432
|
+
* costs nothing while its last answer stays on screen.
|
|
433
|
+
* @module dsh-pause-session/client/global
|
|
434
|
+
*/
|
|
435
|
+
/** Map one Remote row to the list's structured row. */
|
|
436
|
+
function wireTriageRow(row) {
|
|
437
|
+
return {
|
|
438
|
+
sessionId: row.sessionId,
|
|
439
|
+
phase: row.phase,
|
|
440
|
+
updatedAt: row.updatedAt,
|
|
441
|
+
reading: row.reading,
|
|
442
|
+
...row.lastEvent === void 0 ? {} : { lastEvent: row.lastEvent },
|
|
443
|
+
...row.turn === void 0 ? {} : { turn: row.turn },
|
|
444
|
+
...row.step === void 0 ? {} : { step: row.step },
|
|
445
|
+
traces: row.traces.map((trace) => ({
|
|
446
|
+
tool: trace.tool,
|
|
447
|
+
callId: trace.callId ?? ""
|
|
448
|
+
})),
|
|
449
|
+
owed: row.owed,
|
|
450
|
+
wakeable: row.wakeable,
|
|
451
|
+
rearmGoal: row.rearmGoal
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
const INITIAL = {
|
|
455
|
+
global: void 0,
|
|
456
|
+
panelOpen: false,
|
|
457
|
+
triage: void 0
|
|
458
|
+
};
|
|
459
|
+
/**
|
|
460
|
+
* The session a whole-app action is addressed to.
|
|
461
|
+
*
|
|
462
|
+
* A subagent's own session is never addressed: its agent belongs to a parent
|
|
463
|
+
* and is not the host's business to drive from the shell. Among the rest, the
|
|
464
|
+
* one on screen is the best address (its agent is live by construction), then
|
|
465
|
+
* any session the host reports as running, then any at all.
|
|
466
|
+
* @param state - the session list snapshot the shell provides.
|
|
467
|
+
* @returns the address, or `undefined` when the app has no session to ask through.
|
|
468
|
+
*/
|
|
469
|
+
function addressingSession(state) {
|
|
470
|
+
const usable = state.ids.filter((id) => {
|
|
471
|
+
const row = state.byId[String(id)];
|
|
472
|
+
return row !== void 0 && row.origin !== "subagent" && row.parentId === void 0;
|
|
473
|
+
});
|
|
474
|
+
return usable.find((id) => (state.byId[String(id)]?.retainedBy?.mainView ?? 0) > 0) ?? usable.find((id) => state.byId[String(id)]?.running === true) ?? usable[0];
|
|
475
|
+
}
|
|
476
|
+
/** Owns the published whole-app reading; nothing else writes that state. */
|
|
477
|
+
var PauseGlobalControl = class {
|
|
478
|
+
transport;
|
|
479
|
+
lifetime;
|
|
480
|
+
/** State source the whole-app contribution binds its selector hook to. */
|
|
481
|
+
store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(INITIAL);
|
|
482
|
+
/** The session the shell asked this control through; list reads use it. */
|
|
483
|
+
address;
|
|
484
|
+
/** Highest decision-list read requested: an answer older than it is dropped. */
|
|
485
|
+
latestTriage = 0;
|
|
486
|
+
/**
|
|
487
|
+
* @param transport - the native namespace source and actions.
|
|
488
|
+
* @param lifetime - aborts in-flight reads when the plugin unloads.
|
|
489
|
+
*/
|
|
490
|
+
constructor(transport, lifetime) {
|
|
491
|
+
this.transport = transport;
|
|
492
|
+
this.lifetime = lifetime;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* The shell handed this control a session. The first call reads the aggregate;
|
|
496
|
+
* later calls only move where list reads and actions are addressed.
|
|
497
|
+
* @param sessionId - the session the shell asks through.
|
|
498
|
+
*/
|
|
499
|
+
async refresh(sessionId) {
|
|
500
|
+
this.address = sessionId;
|
|
501
|
+
await this.readAggregate();
|
|
502
|
+
}
|
|
503
|
+
/** Apply one pushed snapshot directly. */
|
|
504
|
+
apply(snapshot) {
|
|
505
|
+
this.store.update((state) => {
|
|
506
|
+
state.sessions = snapshot?.sessions;
|
|
507
|
+
});
|
|
508
|
+
this.publish(snapshot === void 0 ? { kind: "unavailable" } : {
|
|
509
|
+
kind: "reported",
|
|
510
|
+
status: snapshot.global
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
/** A pushed snapshot may have moved the aggregate and the open list. */
|
|
514
|
+
refreshAll() {
|
|
515
|
+
if (this.lifetime.aborted) return;
|
|
516
|
+
this.readAggregate();
|
|
517
|
+
if (this.store.getSnapshot().panelOpen) this.refreshTriage();
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Open or close the decision list. Opening asks for the rows; there is no
|
|
521
|
+
* state to show without that answer.
|
|
522
|
+
* @param open - whether the panel should be showing.
|
|
523
|
+
*/
|
|
524
|
+
setPanel(open) {
|
|
525
|
+
this.store.update((state) => {
|
|
526
|
+
state.panelOpen = open;
|
|
527
|
+
});
|
|
528
|
+
if (open) this.refreshTriage();
|
|
529
|
+
}
|
|
530
|
+
/** Ask the host for the decision list for the session the user is on. */
|
|
531
|
+
async refreshTriage() {
|
|
532
|
+
await this.readTriage();
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Take one listed verb on one listed session, addressed through the session
|
|
536
|
+
* the user is on. A refusal is published verbatim rather than silently
|
|
537
|
+
* leaving the previous rows in place.
|
|
538
|
+
* @param sessionId - the listed session to act on.
|
|
539
|
+
* @param action - which listed verb was taken.
|
|
540
|
+
*/
|
|
541
|
+
async decide(sessionId, action) {
|
|
542
|
+
const address = this.address;
|
|
543
|
+
if (address === void 0) return;
|
|
544
|
+
const answer = await this.transport.decide(String(address), sessionId, action, this.lifetime);
|
|
545
|
+
if (!answer.ok) {
|
|
546
|
+
this.store.update((state) => {
|
|
547
|
+
state.error = answer.message;
|
|
548
|
+
});
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
this.store.update((state) => {
|
|
552
|
+
state.error = void 0;
|
|
553
|
+
});
|
|
554
|
+
await this.refreshTriage();
|
|
555
|
+
await this.reread(address);
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Press the pill: park everything, or release everything the park owns.
|
|
559
|
+
* Which one it is comes from the host's own last answer, never from a local
|
|
560
|
+
* flip; the state shown afterwards is the host's answer again.
|
|
561
|
+
* @param sessionId - the session to address the verb to.
|
|
562
|
+
*/
|
|
563
|
+
async toggle(sessionId) {
|
|
564
|
+
const current = this.store.getSnapshot().global;
|
|
565
|
+
if (current === void 0 || current.kind !== "reported") return;
|
|
566
|
+
const action = globalPauseView(current).action;
|
|
567
|
+
if (action === "none") return;
|
|
568
|
+
const answer = await this.transport.act({
|
|
569
|
+
action,
|
|
570
|
+
sessionId: String(sessionId)
|
|
571
|
+
}, this.lifetime);
|
|
572
|
+
if (!answer.ok) {
|
|
573
|
+
this.store.update((state) => {
|
|
574
|
+
state.error = answer.message;
|
|
575
|
+
});
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
this.store.update((state) => {
|
|
579
|
+
state.error = void 0;
|
|
580
|
+
});
|
|
581
|
+
await this.reread(sessionId);
|
|
582
|
+
}
|
|
583
|
+
/** Read the aggregate once and publish it. */
|
|
584
|
+
async readAggregate() {
|
|
585
|
+
const snapshot = await this.transport.source.read(this.lifetime);
|
|
586
|
+
if (snapshot === void 0) {
|
|
587
|
+
this.publish({ kind: "unavailable" });
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
this.store.update((state) => {
|
|
591
|
+
state.sessions = snapshot.sessions;
|
|
592
|
+
});
|
|
593
|
+
this.publish({
|
|
594
|
+
kind: "reported",
|
|
595
|
+
status: snapshot.global
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
async reread(sessionId) {
|
|
599
|
+
this.address = sessionId;
|
|
600
|
+
await this.readAggregate();
|
|
601
|
+
}
|
|
602
|
+
/** One decision-list read, addressed at the session the user is on. */
|
|
603
|
+
async readTriage() {
|
|
604
|
+
const address = this.address;
|
|
605
|
+
if (address === void 0) return;
|
|
606
|
+
const sequence = ++this.latestTriage;
|
|
607
|
+
const reading = await this.readTriageRows(address);
|
|
608
|
+
if (this.latestTriage !== sequence) return;
|
|
609
|
+
this.store.update((state) => {
|
|
610
|
+
state.triage = reading;
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
/** Ask the native namespace for the decision list. */
|
|
614
|
+
async readTriageRows(sessionId) {
|
|
615
|
+
const rows = await this.transport.triage(String(sessionId), this.lifetime);
|
|
616
|
+
return rows === void 0 ? { kind: "unavailable" } : {
|
|
617
|
+
kind: "reported",
|
|
618
|
+
rows: rows.map(wireTriageRow)
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
publish(reading) {
|
|
622
|
+
this.store.update((state) => {
|
|
623
|
+
if (state.global?.kind === reading.kind && (reading.kind === "unavailable" || state.global?.kind === "reported" && JSON.stringify(state.global.status) === JSON.stringify(reading.status))) return;
|
|
624
|
+
state.global = reading;
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
//#endregion
|
|
629
|
+
//#region lib/types/client/remote.js
|
|
630
|
+
/**
|
|
631
|
+
* Client-side bridge from the generated `pauseSession` Remote namespace to the
|
|
632
|
+
* control state machines.
|
|
633
|
+
*
|
|
634
|
+
* The native namespace is the only transport: the stream supplies snapshots and
|
|
635
|
+
* the action methods drive every button. No slash command is involved.
|
|
636
|
+
* @module dsh-pause-session/client/remote
|
|
637
|
+
*/
|
|
638
|
+
/** Convert one wire snapshot to the host-status vocabulary the controls already use. */
|
|
639
|
+
function snapshotOf(wire) {
|
|
640
|
+
return {
|
|
641
|
+
global: {
|
|
642
|
+
...wire.global,
|
|
643
|
+
parkedAt: wire.global.parkedAt,
|
|
644
|
+
draining: wire.global.draining,
|
|
645
|
+
stalled: wire.global.stalled,
|
|
646
|
+
unresumable: wire.global.unresumable,
|
|
647
|
+
unreadTrees: wire.global.unreadTrees,
|
|
648
|
+
jobs: wire.global.jobs,
|
|
649
|
+
blind: wire.global.blind
|
|
650
|
+
},
|
|
651
|
+
sessions: Object.fromEntries(Object.entries(wire.sessions).map(([id, status]) => [id, status]))
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Open the native status stream and expose its latest snapshot to both controls.
|
|
656
|
+
* @param remote - the generated Remote namespace.
|
|
657
|
+
* @param lifetime - client lifetime; aborting it releases the stream.
|
|
658
|
+
* @returns the cached source and its change subscription.
|
|
659
|
+
*/
|
|
660
|
+
function openRemoteSource(remote, lifetime) {
|
|
661
|
+
let latest;
|
|
662
|
+
let failed = false;
|
|
663
|
+
let first;
|
|
664
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
665
|
+
const snapshotListeners = /* @__PURE__ */ new Set();
|
|
666
|
+
const notify = () => {
|
|
667
|
+
for (const listener of [...listeners]) listener();
|
|
668
|
+
for (const listener of [...snapshotListeners]) listener(failed ? void 0 : latest);
|
|
669
|
+
};
|
|
670
|
+
new Promise((resolve) => {
|
|
671
|
+
first = resolve;
|
|
672
|
+
});
|
|
673
|
+
(async () => {
|
|
674
|
+
try {
|
|
675
|
+
for await (const snapshot of remote.observe(lifetime)) {
|
|
676
|
+
latest = snapshotOf(snapshot);
|
|
677
|
+
first?.();
|
|
678
|
+
first = void 0;
|
|
679
|
+
notify();
|
|
680
|
+
}
|
|
681
|
+
} catch {
|
|
682
|
+
failed = true;
|
|
683
|
+
latest = void 0;
|
|
684
|
+
notify();
|
|
685
|
+
} finally {
|
|
686
|
+
if (!lifetime.aborted) {
|
|
687
|
+
failed = true;
|
|
688
|
+
latest = void 0;
|
|
689
|
+
}
|
|
690
|
+
first?.();
|
|
691
|
+
first = void 0;
|
|
692
|
+
notify();
|
|
693
|
+
}
|
|
694
|
+
})();
|
|
695
|
+
return {
|
|
696
|
+
onChange: (listener) => {
|
|
697
|
+
listeners.add(listener);
|
|
698
|
+
return () => {
|
|
699
|
+
listeners.delete(listener);
|
|
700
|
+
};
|
|
701
|
+
},
|
|
702
|
+
onSnapshot: (listener) => {
|
|
703
|
+
snapshotListeners.add(listener);
|
|
704
|
+
return () => {
|
|
705
|
+
snapshotListeners.delete(listener);
|
|
706
|
+
};
|
|
707
|
+
},
|
|
708
|
+
read: async (signal) => {
|
|
709
|
+
if (latest === void 0 && !failed) await new Promise((resolve) => {
|
|
710
|
+
const done = () => {
|
|
711
|
+
signal?.removeEventListener("abort", done);
|
|
712
|
+
resolve();
|
|
713
|
+
};
|
|
714
|
+
first = () => {
|
|
715
|
+
first = void 0;
|
|
716
|
+
done();
|
|
717
|
+
};
|
|
718
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
719
|
+
if (latest !== void 0 || failed) done();
|
|
720
|
+
});
|
|
721
|
+
signal?.throwIfAborted();
|
|
722
|
+
return failed ? void 0 : latest;
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Build the direct transport over one mounted Remote namespace.
|
|
728
|
+
* @param remote - the generated `pauseSession` namespace.
|
|
729
|
+
* @param lifetime - client lifetime.
|
|
730
|
+
* @returns the source and action methods the controls use.
|
|
731
|
+
*/
|
|
732
|
+
function remoteTransport(remote, lifetime) {
|
|
733
|
+
const source = openRemoteSource(remote, lifetime);
|
|
734
|
+
const failed = () => ({
|
|
735
|
+
ok: false,
|
|
736
|
+
message: "pause action failed"
|
|
737
|
+
});
|
|
738
|
+
return {
|
|
739
|
+
source,
|
|
740
|
+
act: async (request, signal) => {
|
|
741
|
+
const answer = await remote.act(request, signal);
|
|
742
|
+
return answer.ok ? answer.value ?? failed() : failed();
|
|
743
|
+
},
|
|
744
|
+
triage: async (caller, signal) => {
|
|
745
|
+
const answer = await remote.triage({ caller }, signal);
|
|
746
|
+
return answer.ok ? answer.value : void 0;
|
|
747
|
+
},
|
|
748
|
+
decide: async (caller, target, decision, signal) => {
|
|
749
|
+
const answer = await remote.decide({
|
|
750
|
+
caller,
|
|
751
|
+
target,
|
|
752
|
+
decision
|
|
753
|
+
}, signal);
|
|
754
|
+
return answer.ok ? answer.value ?? failed() : failed();
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
//#endregion
|
|
759
|
+
//#region src/client/zod-lite.ts
|
|
760
|
+
/** Build one identity codec node. */
|
|
761
|
+
function node() {
|
|
762
|
+
return {
|
|
763
|
+
parse: (value) => value,
|
|
764
|
+
safeParse: (value) => ({
|
|
765
|
+
success: true,
|
|
766
|
+
data: value
|
|
767
|
+
}),
|
|
768
|
+
readonly() {
|
|
769
|
+
return this;
|
|
770
|
+
},
|
|
771
|
+
optional() {
|
|
772
|
+
return this;
|
|
773
|
+
},
|
|
774
|
+
describe() {
|
|
775
|
+
return this;
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
/** The `z` namespace the generated client contribution expects. */
|
|
780
|
+
const z = {
|
|
781
|
+
string: node,
|
|
782
|
+
number: node,
|
|
783
|
+
boolean: node,
|
|
784
|
+
undefined: node,
|
|
785
|
+
literal: node,
|
|
786
|
+
union: node,
|
|
787
|
+
array: node,
|
|
788
|
+
record: node,
|
|
789
|
+
object: node,
|
|
790
|
+
strictObject: node,
|
|
791
|
+
enum: node
|
|
792
|
+
};
|
|
793
|
+
//#endregion
|
|
794
|
+
//#region ../../deepseek-harness/packages/typert/protocol/lib/types/remote-info.js
|
|
795
|
+
/** Lazy assembly of generated Remote definitions using caller-supplied Zod; no runtime imports. */
|
|
796
|
+
/**
|
|
797
|
+
* Retain one generated definition per endpoint without constructing parsers or projections.
|
|
798
|
+
* The class instance builds its shared descriptor/method index on first access;
|
|
799
|
+
* input schemas and JSON Schema projections are cached only when requested.
|
|
800
|
+
* @param spec - compiler-produced method facts and Zod factories.
|
|
801
|
+
* @param zod - the generated artifact's Zod runtime for named-input parsers.
|
|
802
|
+
* @returns a lazy, mountable info instance with no registration or transport effects.
|
|
803
|
+
*/
|
|
804
|
+
function createTypertRemoteInfo(spec, zod) {
|
|
805
|
+
return new RemoteInfo(spec, zod);
|
|
806
|
+
}
|
|
807
|
+
var RemoteInfo = class {
|
|
808
|
+
spec;
|
|
809
|
+
zod;
|
|
810
|
+
index;
|
|
811
|
+
constructor(spec, zod) {
|
|
812
|
+
this.spec = spec;
|
|
813
|
+
this.zod = zod;
|
|
814
|
+
}
|
|
815
|
+
get package() {
|
|
816
|
+
return this.spec.package;
|
|
817
|
+
}
|
|
818
|
+
get descriptors() {
|
|
819
|
+
return this.resolve().descriptors;
|
|
820
|
+
}
|
|
821
|
+
get methods() {
|
|
822
|
+
return this.resolve().methods;
|
|
823
|
+
}
|
|
824
|
+
resolve() {
|
|
825
|
+
if (this.index !== void 0) return this.index;
|
|
826
|
+
const zod = this.zod;
|
|
827
|
+
const descriptors = [];
|
|
828
|
+
const methods = Object.create(null);
|
|
829
|
+
for (const [endpoint, definition] of Object.entries(this.spec.methods)) {
|
|
830
|
+
const separator = endpoint.indexOf("/");
|
|
831
|
+
const namespace = endpoint.slice(0, separator);
|
|
832
|
+
const method = endpoint.slice(separator + 1);
|
|
833
|
+
const parameters = definition.parameters.map((parameter) => ({
|
|
834
|
+
...parameter,
|
|
835
|
+
wire: parameter.wire ?? parameter.name
|
|
836
|
+
}));
|
|
837
|
+
const descriptor = {
|
|
838
|
+
...definition,
|
|
839
|
+
id: `${this.spec.package}#${endpoint}`,
|
|
840
|
+
namespace,
|
|
841
|
+
method,
|
|
842
|
+
parameters,
|
|
843
|
+
result: definition.result.description === void 0 ? definition.result : new ResultValue(definition.result)
|
|
844
|
+
};
|
|
845
|
+
if (definition.invocation.kind === "direct") {
|
|
846
|
+
const inputs = [];
|
|
847
|
+
methods[endpoint] = Object.assign(descriptor, {
|
|
848
|
+
input(options) {
|
|
849
|
+
const strict = options?.strict === true;
|
|
850
|
+
return inputs[strict ? 1 : 0] ??= new NamedInput(parameters, strict, zod);
|
|
851
|
+
},
|
|
852
|
+
invoke(remote, input, signal) {
|
|
853
|
+
const named = input;
|
|
854
|
+
const values = parameters.map((parameter) => named[parameter.wire]);
|
|
855
|
+
if (definition.cancellation !== void 0) values.push(signal);
|
|
856
|
+
const receiver = Reflect.get(remote, namespace);
|
|
857
|
+
return Reflect.get(receiver, method).apply(receiver, values);
|
|
858
|
+
}
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
descriptors.push(descriptor);
|
|
862
|
+
}
|
|
863
|
+
return this.index = {
|
|
864
|
+
descriptors,
|
|
865
|
+
methods
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
function optional(parameter) {
|
|
870
|
+
return parameter.source === "json" && parameter.acceptsUndefined === true;
|
|
871
|
+
}
|
|
872
|
+
var NamedInput = class {
|
|
873
|
+
parameters;
|
|
874
|
+
strict;
|
|
875
|
+
zod;
|
|
876
|
+
schema;
|
|
877
|
+
projection;
|
|
878
|
+
constructor(parameters, strict, zod) {
|
|
879
|
+
this.parameters = parameters;
|
|
880
|
+
this.strict = strict;
|
|
881
|
+
this.zod = zod;
|
|
882
|
+
}
|
|
883
|
+
codec(parameter) {
|
|
884
|
+
return this.strict ? parameter.strictCodec : parameter.codec;
|
|
885
|
+
}
|
|
886
|
+
create = () => this.schema ??= this.zod.strictObject(Object.fromEntries(this.parameters.map((parameter) => {
|
|
887
|
+
const value = this.codec(parameter).create();
|
|
888
|
+
return [parameter.wire, optional(parameter) ? value.optional() : value.nonoptional()];
|
|
889
|
+
})));
|
|
890
|
+
get jsonSchema() {
|
|
891
|
+
return this.project().jsonSchema;
|
|
892
|
+
}
|
|
893
|
+
get jsonSchemaError() {
|
|
894
|
+
return this.project().jsonSchemaError;
|
|
895
|
+
}
|
|
896
|
+
project() {
|
|
897
|
+
if (this.projection !== void 0) return this.projection;
|
|
898
|
+
const unavailable = this.parameters.find((parameter) => this.codec(parameter).jsonSchema === void 0);
|
|
899
|
+
if (unavailable !== void 0) return this.projection = { jsonSchemaError: this.codec(unavailable).jsonSchemaError ?? `No JSON Schema for parameter ${unavailable.wire}` };
|
|
900
|
+
return this.projection = { jsonSchema: {
|
|
901
|
+
type: "object",
|
|
902
|
+
properties: Object.fromEntries(this.parameters.map((parameter) => [parameter.wire, {
|
|
903
|
+
...this.codec(parameter).jsonSchema,
|
|
904
|
+
...parameter.description === void 0 ? {} : { description: parameter.description }
|
|
905
|
+
}])),
|
|
906
|
+
required: this.parameters.filter((parameter) => !optional(parameter)).map((parameter) => parameter.wire),
|
|
907
|
+
additionalProperties: false
|
|
908
|
+
} };
|
|
909
|
+
}
|
|
910
|
+
};
|
|
911
|
+
var ResultValue = class {
|
|
912
|
+
spec;
|
|
913
|
+
projection;
|
|
914
|
+
constructor(spec) {
|
|
915
|
+
this.spec = spec;
|
|
916
|
+
}
|
|
917
|
+
get mode() {
|
|
918
|
+
return this.spec.mode;
|
|
919
|
+
}
|
|
920
|
+
get typeSymbol() {
|
|
921
|
+
return this.spec.typeSymbol;
|
|
922
|
+
}
|
|
923
|
+
get create() {
|
|
924
|
+
return this.spec.create;
|
|
925
|
+
}
|
|
926
|
+
get decode() {
|
|
927
|
+
return this.spec.decode;
|
|
928
|
+
}
|
|
929
|
+
get encode() {
|
|
930
|
+
return this.spec.encode;
|
|
931
|
+
}
|
|
932
|
+
get description() {
|
|
933
|
+
return this.spec.description;
|
|
934
|
+
}
|
|
935
|
+
get jsonSchemaError() {
|
|
936
|
+
return this.spec.jsonSchemaError;
|
|
937
|
+
}
|
|
938
|
+
get jsonSchema() {
|
|
939
|
+
if (this.projection === void 0) {
|
|
940
|
+
const schema = this.spec.jsonSchema;
|
|
941
|
+
this.projection = { value: schema === void 0 ? void 0 : {
|
|
942
|
+
...schema,
|
|
943
|
+
description: this.spec.description
|
|
944
|
+
} };
|
|
945
|
+
}
|
|
946
|
+
return this.projection.value;
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
//#endregion
|
|
950
|
+
//#region lib/typert.remote-client.js
|
|
951
|
+
let dsh_pause_session_pauseSession_act_parameter_0$schema$value;
|
|
952
|
+
const dsh_pause_session_pauseSession_act_parameter_0$schema = () => dsh_pause_session_pauseSession_act_parameter_0$schema$value ??= z.object({
|
|
953
|
+
"action": z.union([
|
|
954
|
+
z.literal("pause"),
|
|
955
|
+
z.literal("resume"),
|
|
956
|
+
z.literal("pause-all"),
|
|
957
|
+
z.literal("resume-all"),
|
|
958
|
+
z.literal("cancel-all"),
|
|
959
|
+
z.literal("goal")
|
|
960
|
+
]).readonly(),
|
|
961
|
+
"sessionId": z.string().readonly().describe("The Session the control is addressed through.")
|
|
962
|
+
});
|
|
963
|
+
let dsh_pause_session_pauseSession_act_result$schema$value;
|
|
964
|
+
const dsh_pause_session_pauseSession_act_result$schema = () => dsh_pause_session_pauseSession_act_result$schema$value ??= z.object({
|
|
965
|
+
"ok": z.boolean().readonly(),
|
|
966
|
+
"message": z.string().readonly()
|
|
967
|
+
});
|
|
968
|
+
let dsh_pause_session_pauseSession_decide_parameter_0$schema$value;
|
|
969
|
+
const dsh_pause_session_pauseSession_decide_parameter_0$schema = () => dsh_pause_session_pauseSession_decide_parameter_0$schema$value ??= z.object({
|
|
970
|
+
"caller": z.string().readonly(),
|
|
971
|
+
"target": z.string().readonly(),
|
|
972
|
+
"decision": z.union([
|
|
973
|
+
z.literal("goal"),
|
|
974
|
+
z.literal("continue"),
|
|
975
|
+
z.literal("note"),
|
|
976
|
+
z.literal("review"),
|
|
977
|
+
z.literal("leave")
|
|
978
|
+
]).readonly()
|
|
979
|
+
});
|
|
980
|
+
let dsh_pause_session_pauseSession_decide_result$schema$value;
|
|
981
|
+
const dsh_pause_session_pauseSession_decide_result$schema = () => dsh_pause_session_pauseSession_decide_result$schema$value ??= z.object({
|
|
982
|
+
"ok": z.boolean().readonly(),
|
|
983
|
+
"message": z.string().readonly()
|
|
984
|
+
});
|
|
985
|
+
let dsh_pause_session_pauseSession_observe_result$schema$value;
|
|
986
|
+
const dsh_pause_session_pauseSession_observe_result$schema = () => dsh_pause_session_pauseSession_observe_result$schema$value ??= z.object({
|
|
987
|
+
"global": z.object({
|
|
988
|
+
"verdict": z.union([
|
|
989
|
+
z.literal("idle"),
|
|
990
|
+
z.literal("waiting"),
|
|
991
|
+
z.literal("safe")
|
|
992
|
+
]).readonly(),
|
|
993
|
+
"registered": z.number().readonly(),
|
|
994
|
+
"safe": z.number().readonly(),
|
|
995
|
+
"parkedAt": z.union([z.undefined(), z.string()]).readonly().optional(),
|
|
996
|
+
"draining": z.array(z.string()).readonly(),
|
|
997
|
+
"parking": z.number().readonly(),
|
|
998
|
+
"stalled": z.array(z.string()).readonly(),
|
|
999
|
+
"unresumable": z.array(z.string()).readonly(),
|
|
1000
|
+
"unreadTrees": z.array(z.string()).readonly(),
|
|
1001
|
+
"jobs": z.array(z.string()).readonly(),
|
|
1002
|
+
"blind": z.array(z.string()).readonly()
|
|
1003
|
+
}).readonly(),
|
|
1004
|
+
"sessions": z.record(z.string(), z.object({
|
|
1005
|
+
"phase": z.union([
|
|
1006
|
+
z.literal("safe"),
|
|
1007
|
+
z.literal("active"),
|
|
1008
|
+
z.literal("draining"),
|
|
1009
|
+
z.literal("parking"),
|
|
1010
|
+
z.literal("flush-failed")
|
|
1011
|
+
]).readonly(),
|
|
1012
|
+
"runningTools": z.array(z.string()).readonly(),
|
|
1013
|
+
"rearmGoal": z.union([
|
|
1014
|
+
z.undefined(),
|
|
1015
|
+
z.literal(false),
|
|
1016
|
+
z.literal(true)
|
|
1017
|
+
]).readonly().optional()
|
|
1018
|
+
})).readonly().readonly()
|
|
1019
|
+
});
|
|
1020
|
+
let dsh_pause_session_pauseSession_snapshot_result$schema$value;
|
|
1021
|
+
const dsh_pause_session_pauseSession_snapshot_result$schema = () => dsh_pause_session_pauseSession_snapshot_result$schema$value ??= z.object({
|
|
1022
|
+
"global": z.object({
|
|
1023
|
+
"verdict": z.union([
|
|
1024
|
+
z.literal("idle"),
|
|
1025
|
+
z.literal("waiting"),
|
|
1026
|
+
z.literal("safe")
|
|
1027
|
+
]).readonly(),
|
|
1028
|
+
"registered": z.number().readonly(),
|
|
1029
|
+
"safe": z.number().readonly(),
|
|
1030
|
+
"parkedAt": z.union([z.undefined(), z.string()]).readonly().optional(),
|
|
1031
|
+
"draining": z.array(z.string()).readonly(),
|
|
1032
|
+
"parking": z.number().readonly(),
|
|
1033
|
+
"stalled": z.array(z.string()).readonly(),
|
|
1034
|
+
"unresumable": z.array(z.string()).readonly(),
|
|
1035
|
+
"unreadTrees": z.array(z.string()).readonly(),
|
|
1036
|
+
"jobs": z.array(z.string()).readonly(),
|
|
1037
|
+
"blind": z.array(z.string()).readonly()
|
|
1038
|
+
}).readonly(),
|
|
1039
|
+
"sessions": z.record(z.string(), z.object({
|
|
1040
|
+
"phase": z.union([
|
|
1041
|
+
z.literal("safe"),
|
|
1042
|
+
z.literal("active"),
|
|
1043
|
+
z.literal("draining"),
|
|
1044
|
+
z.literal("parking"),
|
|
1045
|
+
z.literal("flush-failed")
|
|
1046
|
+
]).readonly(),
|
|
1047
|
+
"runningTools": z.array(z.string()).readonly(),
|
|
1048
|
+
"rearmGoal": z.union([
|
|
1049
|
+
z.undefined(),
|
|
1050
|
+
z.literal(false),
|
|
1051
|
+
z.literal(true)
|
|
1052
|
+
]).readonly().optional()
|
|
1053
|
+
})).readonly().readonly()
|
|
1054
|
+
});
|
|
1055
|
+
let dsh_pause_session_pauseSession_triage_parameter_0$schema$value;
|
|
1056
|
+
const dsh_pause_session_pauseSession_triage_parameter_0$schema = () => dsh_pause_session_pauseSession_triage_parameter_0$schema$value ??= z.object({ "caller": z.string().readonly() });
|
|
1057
|
+
let dsh_pause_session_pauseSession_triage_result$schema$value;
|
|
1058
|
+
const dsh_pause_session_pauseSession_triage_result$schema = () => dsh_pause_session_pauseSession_triage_result$schema$value ??= z.array(z.object({
|
|
1059
|
+
"sessionId": z.string().readonly(),
|
|
1060
|
+
"phase": z.union([
|
|
1061
|
+
z.literal("draining"),
|
|
1062
|
+
z.literal("parking"),
|
|
1063
|
+
z.literal("flush-failed")
|
|
1064
|
+
]).readonly(),
|
|
1065
|
+
"updatedAt": z.number().readonly(),
|
|
1066
|
+
"reading": z.union([z.literal("read"), z.literal("unreadable")]).readonly(),
|
|
1067
|
+
"lastEvent": z.union([z.undefined(), z.string()]).readonly().optional(),
|
|
1068
|
+
"turn": z.union([z.undefined(), z.number()]).readonly().optional(),
|
|
1069
|
+
"step": z.union([z.undefined(), z.number()]).readonly().optional(),
|
|
1070
|
+
"traces": z.array(z.object({
|
|
1071
|
+
"tool": z.string().readonly(),
|
|
1072
|
+
"callId": z.string().readonly()
|
|
1073
|
+
})).readonly(),
|
|
1074
|
+
"owed": z.boolean().readonly(),
|
|
1075
|
+
"wakeable": z.boolean().readonly(),
|
|
1076
|
+
"rearmGoal": z.boolean().readonly()
|
|
1077
|
+
}));
|
|
1078
|
+
let dsh_pause_session_pauseSession_act_parameter_0_strict$schema$value;
|
|
1079
|
+
const dsh_pause_session_pauseSession_act_parameter_0_strict$schema = () => dsh_pause_session_pauseSession_act_parameter_0_strict$schema$value ??= z.strictObject({
|
|
1080
|
+
"action": z.union([
|
|
1081
|
+
z.literal("pause"),
|
|
1082
|
+
z.literal("resume"),
|
|
1083
|
+
z.literal("pause-all"),
|
|
1084
|
+
z.literal("resume-all"),
|
|
1085
|
+
z.literal("cancel-all"),
|
|
1086
|
+
z.literal("goal")
|
|
1087
|
+
]).readonly(),
|
|
1088
|
+
"sessionId": z.string().readonly().describe("The Session the control is addressed through.")
|
|
1089
|
+
});
|
|
1090
|
+
let dsh_pause_session_pauseSession_decide_parameter_0_strict$schema$value;
|
|
1091
|
+
const dsh_pause_session_pauseSession_decide_parameter_0_strict$schema = () => dsh_pause_session_pauseSession_decide_parameter_0_strict$schema$value ??= z.strictObject({
|
|
1092
|
+
"caller": z.string().readonly(),
|
|
1093
|
+
"target": z.string().readonly(),
|
|
1094
|
+
"decision": z.union([
|
|
1095
|
+
z.literal("goal"),
|
|
1096
|
+
z.literal("continue"),
|
|
1097
|
+
z.literal("note"),
|
|
1098
|
+
z.literal("review"),
|
|
1099
|
+
z.literal("leave")
|
|
1100
|
+
]).readonly()
|
|
1101
|
+
});
|
|
1102
|
+
let dsh_pause_session_pauseSession_triage_parameter_0_strict$schema$value;
|
|
1103
|
+
const dsh_pause_session_pauseSession_triage_parameter_0_strict$schema = () => dsh_pause_session_pauseSession_triage_parameter_0_strict$schema$value ??= z.strictObject({ "caller": z.string().readonly() });
|
|
1104
|
+
const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
1105
|
+
package: "dsh-pause-session",
|
|
1106
|
+
methods: {
|
|
1107
|
+
"pauseSession/act": {
|
|
1108
|
+
service: "pauseSession",
|
|
1109
|
+
description: "Pause, resume, press every tree, resume every clean park, or flip one Session's goal re-arm.",
|
|
1110
|
+
invocation: { kind: "direct" },
|
|
1111
|
+
parameters: [{
|
|
1112
|
+
name: "request",
|
|
1113
|
+
description: "the button action.",
|
|
1114
|
+
source: "json",
|
|
1115
|
+
codec: {
|
|
1116
|
+
mode: "strict",
|
|
1117
|
+
typeSymbol: "dsh-pause-session/types#PauseActionRequest",
|
|
1118
|
+
create: dsh_pause_session_pauseSession_act_parameter_0$schema,
|
|
1119
|
+
jsonSchema: {
|
|
1120
|
+
"type": "object",
|
|
1121
|
+
"properties": {
|
|
1122
|
+
"action": {
|
|
1123
|
+
"type": "string",
|
|
1124
|
+
"enum": [
|
|
1125
|
+
"pause",
|
|
1126
|
+
"resume",
|
|
1127
|
+
"pause-all",
|
|
1128
|
+
"resume-all",
|
|
1129
|
+
"cancel-all",
|
|
1130
|
+
"goal"
|
|
1131
|
+
]
|
|
1132
|
+
},
|
|
1133
|
+
"sessionId": {
|
|
1134
|
+
"type": "string",
|
|
1135
|
+
"description": "The Session the control is addressed through."
|
|
1136
|
+
}
|
|
1137
|
+
},
|
|
1138
|
+
"required": ["action", "sessionId"],
|
|
1139
|
+
"additionalProperties": true
|
|
1140
|
+
}
|
|
1141
|
+
},
|
|
1142
|
+
strictCodec: {
|
|
1143
|
+
mode: "strict",
|
|
1144
|
+
typeSymbol: "dsh-pause-session/types#PauseActionRequest",
|
|
1145
|
+
create: dsh_pause_session_pauseSession_act_parameter_0_strict$schema,
|
|
1146
|
+
jsonSchema: {
|
|
1147
|
+
"type": "object",
|
|
1148
|
+
"properties": {
|
|
1149
|
+
"action": {
|
|
1150
|
+
"type": "string",
|
|
1151
|
+
"enum": [
|
|
1152
|
+
"pause",
|
|
1153
|
+
"resume",
|
|
1154
|
+
"pause-all",
|
|
1155
|
+
"resume-all",
|
|
1156
|
+
"cancel-all",
|
|
1157
|
+
"goal"
|
|
1158
|
+
]
|
|
1159
|
+
},
|
|
1160
|
+
"sessionId": {
|
|
1161
|
+
"type": "string",
|
|
1162
|
+
"description": "The Session the control is addressed through."
|
|
1163
|
+
}
|
|
1164
|
+
},
|
|
1165
|
+
"required": ["action", "sessionId"],
|
|
1166
|
+
"additionalProperties": false
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}],
|
|
1170
|
+
cancellation: { parameter: "signal" },
|
|
1171
|
+
result: {
|
|
1172
|
+
mode: "strict",
|
|
1173
|
+
typeSymbol: "dsh-pause-session/types#PauseActionResultWire",
|
|
1174
|
+
create: dsh_pause_session_pauseSession_act_result$schema,
|
|
1175
|
+
description: "the user-facing outcome.",
|
|
1176
|
+
jsonSchema: {
|
|
1177
|
+
"type": "object",
|
|
1178
|
+
"properties": {
|
|
1179
|
+
"ok": { "type": "boolean" },
|
|
1180
|
+
"message": { "type": "string" }
|
|
1181
|
+
},
|
|
1182
|
+
"required": ["ok", "message"],
|
|
1183
|
+
"additionalProperties": true
|
|
1184
|
+
}
|
|
1185
|
+
},
|
|
1186
|
+
sourceLocation: {
|
|
1187
|
+
"file": "packages/dsh-pause-session/src/remote.ts",
|
|
1188
|
+
"line": 239,
|
|
1189
|
+
"column": 9
|
|
1190
|
+
}
|
|
1191
|
+
},
|
|
1192
|
+
"pauseSession/decide": {
|
|
1193
|
+
service: "pauseSession",
|
|
1194
|
+
description: "Take one decision on one listed Session.",
|
|
1195
|
+
invocation: { kind: "direct" },
|
|
1196
|
+
parameters: [{
|
|
1197
|
+
name: "request",
|
|
1198
|
+
description: "the caller, target, and decision.",
|
|
1199
|
+
source: "json",
|
|
1200
|
+
codec: {
|
|
1201
|
+
mode: "strict",
|
|
1202
|
+
typeSymbol: "dsh-pause-session/types#PauseDecisionRequest",
|
|
1203
|
+
create: dsh_pause_session_pauseSession_decide_parameter_0$schema,
|
|
1204
|
+
jsonSchema: {
|
|
1205
|
+
"type": "object",
|
|
1206
|
+
"properties": {
|
|
1207
|
+
"caller": { "type": "string" },
|
|
1208
|
+
"target": { "type": "string" },
|
|
1209
|
+
"decision": {
|
|
1210
|
+
"type": "string",
|
|
1211
|
+
"enum": [
|
|
1212
|
+
"goal",
|
|
1213
|
+
"continue",
|
|
1214
|
+
"note",
|
|
1215
|
+
"review",
|
|
1216
|
+
"leave"
|
|
1217
|
+
]
|
|
1218
|
+
}
|
|
1219
|
+
},
|
|
1220
|
+
"required": [
|
|
1221
|
+
"caller",
|
|
1222
|
+
"target",
|
|
1223
|
+
"decision"
|
|
1224
|
+
],
|
|
1225
|
+
"additionalProperties": true
|
|
1226
|
+
}
|
|
1227
|
+
},
|
|
1228
|
+
strictCodec: {
|
|
1229
|
+
mode: "strict",
|
|
1230
|
+
typeSymbol: "dsh-pause-session/types#PauseDecisionRequest",
|
|
1231
|
+
create: dsh_pause_session_pauseSession_decide_parameter_0_strict$schema,
|
|
1232
|
+
jsonSchema: {
|
|
1233
|
+
"type": "object",
|
|
1234
|
+
"properties": {
|
|
1235
|
+
"caller": { "type": "string" },
|
|
1236
|
+
"target": { "type": "string" },
|
|
1237
|
+
"decision": {
|
|
1238
|
+
"type": "string",
|
|
1239
|
+
"enum": [
|
|
1240
|
+
"goal",
|
|
1241
|
+
"continue",
|
|
1242
|
+
"note",
|
|
1243
|
+
"review",
|
|
1244
|
+
"leave"
|
|
1245
|
+
]
|
|
1246
|
+
}
|
|
1247
|
+
},
|
|
1248
|
+
"required": [
|
|
1249
|
+
"caller",
|
|
1250
|
+
"target",
|
|
1251
|
+
"decision"
|
|
1252
|
+
],
|
|
1253
|
+
"additionalProperties": false
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
}],
|
|
1257
|
+
cancellation: { parameter: "signal" },
|
|
1258
|
+
result: {
|
|
1259
|
+
mode: "strict",
|
|
1260
|
+
typeSymbol: "dsh-pause-session/types#PauseActionResultWire",
|
|
1261
|
+
create: dsh_pause_session_pauseSession_decide_result$schema,
|
|
1262
|
+
description: "the user-facing outcome.",
|
|
1263
|
+
jsonSchema: {
|
|
1264
|
+
"type": "object",
|
|
1265
|
+
"properties": {
|
|
1266
|
+
"ok": { "type": "boolean" },
|
|
1267
|
+
"message": { "type": "string" }
|
|
1268
|
+
},
|
|
1269
|
+
"required": ["ok", "message"],
|
|
1270
|
+
"additionalProperties": true
|
|
1271
|
+
}
|
|
1272
|
+
},
|
|
1273
|
+
sourceLocation: {
|
|
1274
|
+
"file": "packages/dsh-pause-session/src/remote.ts",
|
|
1275
|
+
"line": 264,
|
|
1276
|
+
"column": 9
|
|
1277
|
+
}
|
|
1278
|
+
},
|
|
1279
|
+
"pauseSession/observe": {
|
|
1280
|
+
service: "pauseSession",
|
|
1281
|
+
description: "Live status: the opening snapshot, then one new snapshot whenever the host reports a change.",
|
|
1282
|
+
mode: "stream",
|
|
1283
|
+
invocation: { kind: "direct" },
|
|
1284
|
+
parameters: [],
|
|
1285
|
+
cancellation: { parameter: "signal" },
|
|
1286
|
+
result: {
|
|
1287
|
+
mode: "strict",
|
|
1288
|
+
typeSymbol: "dsh-pause-session/types#PauseSnapshotWire",
|
|
1289
|
+
create: dsh_pause_session_pauseSession_observe_result$schema,
|
|
1290
|
+
description: "the snapshot stream.",
|
|
1291
|
+
jsonSchemaError: "typert tool schema: selected dictionaries require string keys and unconstrained JSON values"
|
|
1292
|
+
},
|
|
1293
|
+
sourceLocation: {
|
|
1294
|
+
"file": "packages/dsh-pause-session/src/remote.ts",
|
|
1295
|
+
"line": 201,
|
|
1296
|
+
"column": 10
|
|
1297
|
+
}
|
|
1298
|
+
},
|
|
1299
|
+
"pauseSession/snapshot": {
|
|
1300
|
+
service: "pauseSession",
|
|
1301
|
+
description: "One exact snapshot, used by tests and by a reconnect that cannot wait for the first stream item.",
|
|
1302
|
+
invocation: { kind: "direct" },
|
|
1303
|
+
parameters: [],
|
|
1304
|
+
cancellation: { parameter: "signal" },
|
|
1305
|
+
result: {
|
|
1306
|
+
mode: "strict",
|
|
1307
|
+
typeSymbol: "dsh-pause-session/types#PauseSnapshotWire",
|
|
1308
|
+
create: dsh_pause_session_pauseSession_snapshot_result$schema,
|
|
1309
|
+
description: "the current aggregate and session states.",
|
|
1310
|
+
jsonSchemaError: "typert tool schema: selected dictionaries require string keys and unconstrained JSON values"
|
|
1311
|
+
},
|
|
1312
|
+
sourceLocation: {
|
|
1313
|
+
"file": "packages/dsh-pause-session/src/remote.ts",
|
|
1314
|
+
"line": 175,
|
|
1315
|
+
"column": 9
|
|
1316
|
+
}
|
|
1317
|
+
},
|
|
1318
|
+
"pauseSession/triage": {
|
|
1319
|
+
service: "pauseSession",
|
|
1320
|
+
description: "Read the morning decision list.",
|
|
1321
|
+
invocation: { kind: "direct" },
|
|
1322
|
+
parameters: [{
|
|
1323
|
+
name: "request",
|
|
1324
|
+
description: "the calling Session whose list is read.",
|
|
1325
|
+
source: "json",
|
|
1326
|
+
codec: {
|
|
1327
|
+
mode: "strict",
|
|
1328
|
+
typeSymbol: "dsh-pause-session/types#PauseTriageRequest",
|
|
1329
|
+
create: dsh_pause_session_pauseSession_triage_parameter_0$schema,
|
|
1330
|
+
jsonSchema: {
|
|
1331
|
+
"type": "object",
|
|
1332
|
+
"properties": { "caller": { "type": "string" } },
|
|
1333
|
+
"required": ["caller"],
|
|
1334
|
+
"additionalProperties": true
|
|
1335
|
+
}
|
|
1336
|
+
},
|
|
1337
|
+
strictCodec: {
|
|
1338
|
+
mode: "strict",
|
|
1339
|
+
typeSymbol: "dsh-pause-session/types#PauseTriageRequest",
|
|
1340
|
+
create: dsh_pause_session_pauseSession_triage_parameter_0_strict$schema,
|
|
1341
|
+
jsonSchema: {
|
|
1342
|
+
"type": "object",
|
|
1343
|
+
"properties": { "caller": { "type": "string" } },
|
|
1344
|
+
"required": ["caller"],
|
|
1345
|
+
"additionalProperties": false
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
}],
|
|
1349
|
+
cancellation: { parameter: "signal" },
|
|
1350
|
+
result: {
|
|
1351
|
+
mode: "strict",
|
|
1352
|
+
typeSymbol: "dsh-pause-session#pauseSession/triage:result",
|
|
1353
|
+
create: dsh_pause_session_pauseSession_triage_result$schema,
|
|
1354
|
+
description: "the listed rows.",
|
|
1355
|
+
jsonSchema: {
|
|
1356
|
+
"type": "array",
|
|
1357
|
+
"items": {
|
|
1358
|
+
"type": "object",
|
|
1359
|
+
"properties": {
|
|
1360
|
+
"sessionId": { "type": "string" },
|
|
1361
|
+
"phase": {
|
|
1362
|
+
"type": "string",
|
|
1363
|
+
"enum": [
|
|
1364
|
+
"draining",
|
|
1365
|
+
"parking",
|
|
1366
|
+
"flush-failed"
|
|
1367
|
+
]
|
|
1368
|
+
},
|
|
1369
|
+
"updatedAt": { "type": "number" },
|
|
1370
|
+
"reading": {
|
|
1371
|
+
"type": "string",
|
|
1372
|
+
"enum": ["read", "unreadable"]
|
|
1373
|
+
},
|
|
1374
|
+
"lastEvent": { "type": "string" },
|
|
1375
|
+
"turn": { "type": "number" },
|
|
1376
|
+
"step": { "type": "number" },
|
|
1377
|
+
"traces": {
|
|
1378
|
+
"type": "array",
|
|
1379
|
+
"items": {
|
|
1380
|
+
"type": "object",
|
|
1381
|
+
"properties": {
|
|
1382
|
+
"tool": { "type": "string" },
|
|
1383
|
+
"callId": { "type": "string" }
|
|
1384
|
+
},
|
|
1385
|
+
"required": ["tool", "callId"],
|
|
1386
|
+
"additionalProperties": true
|
|
1387
|
+
}
|
|
1388
|
+
},
|
|
1389
|
+
"owed": { "type": "boolean" },
|
|
1390
|
+
"wakeable": { "type": "boolean" },
|
|
1391
|
+
"rearmGoal": { "type": "boolean" }
|
|
1392
|
+
},
|
|
1393
|
+
"required": [
|
|
1394
|
+
"sessionId",
|
|
1395
|
+
"phase",
|
|
1396
|
+
"updatedAt",
|
|
1397
|
+
"reading",
|
|
1398
|
+
"traces",
|
|
1399
|
+
"owed",
|
|
1400
|
+
"wakeable",
|
|
1401
|
+
"rearmGoal"
|
|
1402
|
+
],
|
|
1403
|
+
"additionalProperties": true
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
},
|
|
1407
|
+
sourceLocation: {
|
|
1408
|
+
"file": "packages/dsh-pause-session/src/remote.ts",
|
|
1409
|
+
"line": 252,
|
|
1410
|
+
"column": 9
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
}, z);
|
|
1415
|
+
//#endregion
|
|
1416
|
+
//#region lib/types/client/icons.js
|
|
1417
|
+
/** 16px stroke icon (currentColor): the two bars of a pause. */
|
|
1418
|
+
function PauseIcon() {
|
|
1419
|
+
return (0, react_jsx_runtime.jsxs)("svg", {
|
|
1420
|
+
"aria-hidden": "true",
|
|
1421
|
+
width: 16,
|
|
1422
|
+
height: 16,
|
|
1423
|
+
viewBox: "0 0 24 24",
|
|
1424
|
+
fill: "none",
|
|
1425
|
+
stroke: "currentColor",
|
|
1426
|
+
strokeWidth: 2,
|
|
1427
|
+
strokeLinecap: "round",
|
|
1428
|
+
strokeLinejoin: "round",
|
|
1429
|
+
children: [(0, react_jsx_runtime.jsx)("path", { d: "M9 5v14" }), (0, react_jsx_runtime.jsx)("path", { d: "M15 5v14" })]
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
/** 16px stroke icon (currentColor): the triangle of a resume. */
|
|
1433
|
+
function ResumeIcon() {
|
|
1434
|
+
return (0, react_jsx_runtime.jsx)("svg", {
|
|
1435
|
+
"aria-hidden": "true",
|
|
1436
|
+
width: 16,
|
|
1437
|
+
height: 16,
|
|
1438
|
+
viewBox: "0 0 24 24",
|
|
1439
|
+
fill: "none",
|
|
1440
|
+
stroke: "currentColor",
|
|
1441
|
+
strokeWidth: 2,
|
|
1442
|
+
strokeLinecap: "round",
|
|
1443
|
+
strokeLinejoin: "round",
|
|
1444
|
+
children: (0, react_jsx_runtime.jsx)("path", { d: "M7 4.5v15l12-7.5z" })
|
|
1445
|
+
});
|
|
1446
|
+
}
|
|
1447
|
+
/**
|
|
1448
|
+
* 16px stroke icon (currentColor): the rings of a target, for the goal switch
|
|
1449
|
+
* on the session header. Drawn at 16px like the pause and resume glyphs it sits
|
|
1450
|
+
* beside rather than the 14px marks the two reports use.
|
|
1451
|
+
*/
|
|
1452
|
+
function GoalIcon() {
|
|
1453
|
+
return (0, react_jsx_runtime.jsxs)("svg", {
|
|
1454
|
+
"aria-hidden": "true",
|
|
1455
|
+
width: 16,
|
|
1456
|
+
height: 16,
|
|
1457
|
+
viewBox: "0 0 24 24",
|
|
1458
|
+
fill: "none",
|
|
1459
|
+
stroke: "currentColor",
|
|
1460
|
+
strokeWidth: 2,
|
|
1461
|
+
strokeLinecap: "round",
|
|
1462
|
+
strokeLinejoin: "round",
|
|
1463
|
+
children: [(0, react_jsx_runtime.jsx)("circle", {
|
|
1464
|
+
cx: "12",
|
|
1465
|
+
cy: "12",
|
|
1466
|
+
r: "8"
|
|
1467
|
+
}), (0, react_jsx_runtime.jsx)("circle", {
|
|
1468
|
+
cx: "12",
|
|
1469
|
+
cy: "12",
|
|
1470
|
+
r: "3"
|
|
1471
|
+
})]
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
* 14px stroke icon (currentColor): the mark that a report carries a caveat.
|
|
1476
|
+
* A glyph rather than copy, so the facts it stands for stay in the locale
|
|
1477
|
+
* dictionaries beside everything else the user reads.
|
|
1478
|
+
*/
|
|
1479
|
+
function CaveatIcon() {
|
|
1480
|
+
return (0, react_jsx_runtime.jsxs)("svg", {
|
|
1481
|
+
"aria-hidden": "true",
|
|
1482
|
+
width: 14,
|
|
1483
|
+
height: 14,
|
|
1484
|
+
viewBox: "0 0 24 24",
|
|
1485
|
+
fill: "none",
|
|
1486
|
+
stroke: "currentColor",
|
|
1487
|
+
strokeWidth: 2,
|
|
1488
|
+
strokeLinecap: "round",
|
|
1489
|
+
strokeLinejoin: "round",
|
|
1490
|
+
children: [
|
|
1491
|
+
(0, react_jsx_runtime.jsx)("circle", {
|
|
1492
|
+
cx: "12",
|
|
1493
|
+
cy: "12",
|
|
1494
|
+
r: "9"
|
|
1495
|
+
}),
|
|
1496
|
+
(0, react_jsx_runtime.jsx)("path", { d: "M12 7.5v5.5" }),
|
|
1497
|
+
(0, react_jsx_runtime.jsx)("path", { d: "M12 16.5v.5" })
|
|
1498
|
+
]
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1501
|
+
/** 14px stroke icon (currentColor): the chevron that opens the decision list. */
|
|
1502
|
+
function ChevronIcon() {
|
|
1503
|
+
return (0, react_jsx_runtime.jsx)("svg", {
|
|
1504
|
+
"aria-hidden": "true",
|
|
1505
|
+
width: 14,
|
|
1506
|
+
height: 14,
|
|
1507
|
+
viewBox: "0 0 24 24",
|
|
1508
|
+
fill: "none",
|
|
1509
|
+
stroke: "currentColor",
|
|
1510
|
+
strokeWidth: 2,
|
|
1511
|
+
strokeLinecap: "round",
|
|
1512
|
+
strokeLinejoin: "round",
|
|
1513
|
+
children: (0, react_jsx_runtime.jsx)("path", { d: "M6 15l6-6 6 6" })
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
//#endregion
|
|
1517
|
+
//#region \0dsh-css:src/client/button.module.css.mjs
|
|
1518
|
+
const css = ".FCO1_q_dsp{align-items:center;display:inline-flex;position:relative}.FCO1_q_dspBtn{width:26px;height:26px;color:var(--dsw-alias-label-secondary);cursor:pointer;user-select:none;background:0 0;border:1px solid #0000;border-radius:6px;justify-content:center;align-items:center;padding:0;transition:color .12s,background .12s,border-color .12s;display:inline-flex}.FCO1_q_dspBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l1)}.FCO1_q_dspBtn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}.FCO1_q_dspBtn:disabled{cursor:default;opacity:.5}.FCO1_q_dspBtn:disabled:hover{color:var(--dsw-alias-label-secondary);background:0 0;border-color:#0000}.FCO1_q_dspGoal{width:22px;height:22px;color:var(--dsw-alias-label-tertiary);cursor:pointer;user-select:none;background:0 0;border:1px solid #0000;border-radius:6px;justify-content:center;align-items:center;margin-left:2px;padding:0;transition:color .12s,background .12s,border-color .12s;display:inline-flex}.FCO1_q_dspGoal[aria-pressed=true]{color:var(--dsw-alias-label-secondary)}.FCO1_q_dspGoal:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l1)}.FCO1_q_dspGoal:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}@media (prefers-reduced-motion:reduce){.FCO1_q_dspGoal{transition:none}}.FCO1_q_dspState{color:var(--dsw-alias-label-secondary);white-space:nowrap;user-select:none;padding-left:6px;font-size:12px;line-height:18px}@media (prefers-reduced-motion:reduce){.FCO1_q_dspBtn{transition:none}}.FCO1_q_dspPill{align-items:center;display:inline-flex;position:relative}.FCO1_q_dspPillBtn{max-width:min(38ch,100vw - 48px);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);cursor:pointer;user-select:none;border-radius:999px;align-items:center;gap:6px;padding:5px 10px;font-size:12px;line-height:18px;transition:color .12s,background .12s,border-color .12s;display:inline-flex;box-shadow:0 4px 12px #00000024}.FCO1_q_dspPillBtn:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2)}.FCO1_q_dspPillIcon{justify-content:center;width:28px;height:28px;padding:0}.FCO1_q_dspPillBtn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}.FCO1_q_dspPillBtn:disabled{cursor:default;opacity:.5}.FCO1_q_dspPillText{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.FCO1_q_dspPillDetail{font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-tertiary)}.FCO1_q_dspPillWarn{color:var(--dsw-alias-state-warn-primary,var(--dsw-alias-label-primary));font-weight:600}@media (prefers-reduced-motion:reduce){.FCO1_q_dspPillBtn{transition:none}}.FCO1_q_dspPillTriage{color:var(--dsw-alias-state-warn-primary,var(--dsw-alias-label-primary));background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);cursor:pointer;user-select:none;border-radius:999px;align-items:center;gap:2px;margin-right:4px;padding:4px 8px;font-size:12px;line-height:18px;display:inline-flex;box-shadow:0 4px 12px #00000024}.FCO1_q_dspPillTriage:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2)}.FCO1_q_dspPillTriage:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}.FCO1_q_dspPillPanel{z-index:30;text-align:left;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;flex-direction:column;gap:8px;width:min(52ch,100vw - 48px);max-height:min(60vh,420px);padding:10px 12px;display:flex;position:absolute;top:calc(100% + 6px);right:0;overflow-y:auto;box-shadow:0 8px 24px #00000038}.FCO1_q_dspPillPanelHead{justify-content:space-between;align-items:center;gap:8px;font-weight:600;display:flex}.FCO1_q_dspPillError{color:var(--dsw-alias-state-error-primary);margin:0 0 8px;font-size:12px;line-height:18px}.FCO1_q_dspPillPanelNote{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:18px}.FCO1_q_dspPillRows{flex-direction:column;gap:8px;margin:0;padding:0;list-style:none;display:flex}.FCO1_q_dspPillRow{border:1px solid var(--dsw-alias-border-l1);border-radius:6px;flex-direction:column;gap:4px;padding:8px;display:flex}.FCO1_q_dspPillRowHead{justify-content:space-between;align-items:baseline;gap:8px;display:flex}.FCO1_q_dspPillRowId{word-break:break-all;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.FCO1_q_dspPillRowPhase{color:var(--dsw-alias-state-warn-primary,var(--dsw-alias-label-primary));flex:none;font-size:12px}.FCO1_q_dspPillRowFacts{color:var(--dsw-alias-label-secondary);flex-direction:column;gap:2px;font-size:12px;line-height:18px;display:flex}.FCO1_q_dspPillRowActions{flex-wrap:wrap;gap:6px;padding-top:2px;display:flex}.FCO1_q_dspPillAction{color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l1);cursor:pointer;user-select:none;background:0 0;border-radius:4px;padding:3px 8px;font-size:12px;line-height:16px}.FCO1_q_dspPillAction:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2)}.FCO1_q_dspPillAction:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}";
|
|
1519
|
+
const tagId = "dsh-pause-session/button.module.css";
|
|
1520
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
1521
|
+
const tag = document.createElement("style");
|
|
1522
|
+
tag.dataset.plugin = "dsh-pause-session";
|
|
1523
|
+
tag.dataset.pluginCss = tagId;
|
|
1524
|
+
tag.textContent = css;
|
|
1525
|
+
document.head.appendChild(tag);
|
|
1526
|
+
}
|
|
1527
|
+
var button_module_css_default = {
|
|
1528
|
+
"dsp": "FCO1_q_dsp",
|
|
1529
|
+
"dspBtn": "FCO1_q_dspBtn",
|
|
1530
|
+
"dspGoal": "FCO1_q_dspGoal",
|
|
1531
|
+
"dspPill": "FCO1_q_dspPill",
|
|
1532
|
+
"dspPillAction": "FCO1_q_dspPillAction",
|
|
1533
|
+
"dspPillBtn": "FCO1_q_dspPillBtn",
|
|
1534
|
+
"dspPillDetail": "FCO1_q_dspPillDetail",
|
|
1535
|
+
"dspPillError": "FCO1_q_dspPillError",
|
|
1536
|
+
"dspPillIcon": "FCO1_q_dspPillIcon",
|
|
1537
|
+
"dspPillPanel": "FCO1_q_dspPillPanel",
|
|
1538
|
+
"dspPillPanelHead": "FCO1_q_dspPillPanelHead",
|
|
1539
|
+
"dspPillPanelNote": "FCO1_q_dspPillPanelNote",
|
|
1540
|
+
"dspPillRow": "FCO1_q_dspPillRow",
|
|
1541
|
+
"dspPillRowActions": "FCO1_q_dspPillRowActions",
|
|
1542
|
+
"dspPillRowFacts": "FCO1_q_dspPillRowFacts",
|
|
1543
|
+
"dspPillRowHead": "FCO1_q_dspPillRowHead",
|
|
1544
|
+
"dspPillRowId": "FCO1_q_dspPillRowId",
|
|
1545
|
+
"dspPillRowPhase": "FCO1_q_dspPillRowPhase",
|
|
1546
|
+
"dspPillRows": "FCO1_q_dspPillRows",
|
|
1547
|
+
"dspPillText": "FCO1_q_dspPillText",
|
|
1548
|
+
"dspPillTriage": "FCO1_q_dspPillTriage",
|
|
1549
|
+
"dspPillWarn": "FCO1_q_dspPillWarn",
|
|
1550
|
+
"dspState": "FCO1_q_dspState"
|
|
1551
|
+
};
|
|
1552
|
+
//#endregion
|
|
1553
|
+
//#region lib/types/client/pill.js
|
|
1554
|
+
/**
|
|
1555
|
+
* The whole-app control: one pill in the conversation header's utilities row
|
|
1556
|
+
* that answers "can I close the lid?", presses the park or the release, and —
|
|
1557
|
+
* when something did not stop cleanly — opens the morning decision list.
|
|
1558
|
+
*
|
|
1559
|
+
* The header's right-aligned utilities row is inside the conversation column,
|
|
1560
|
+
* which is where this control belongs: it answers for every session tree, but
|
|
1561
|
+
* it is read while looking at one, and a surface inside the layout is covered
|
|
1562
|
+
* by whatever covers that column — a sidebar or a drawer — instead of floating
|
|
1563
|
+
* above the whole frame. The decision list hangs from the control into the
|
|
1564
|
+
* conversation area below.
|
|
1565
|
+
*
|
|
1566
|
+
* The pill reads the native status stream through `./global.ts`. With no
|
|
1567
|
+
* answer, or with no session to address an action through, it renders nothing
|
|
1568
|
+
* rather than a state it would have to invent. The decision list is
|
|
1569
|
+
* deliberately NOT part of that first read; the panel asks for its own rows
|
|
1570
|
+
* when it opens.
|
|
1571
|
+
* @module dsh-pause-session/client/pill
|
|
1572
|
+
*/
|
|
1573
|
+
/** One listed session's row, with the four decisions. */
|
|
1574
|
+
function TriageSessionRow(props) {
|
|
1575
|
+
const { row, decide, t } = props;
|
|
1576
|
+
return (0, react_jsx_runtime.jsxs)("li", {
|
|
1577
|
+
className: button_module_css_default.dspPillRow,
|
|
1578
|
+
children: [
|
|
1579
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
1580
|
+
className: button_module_css_default.dspPillRowHead,
|
|
1581
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
1582
|
+
className: button_module_css_default.dspPillRowId,
|
|
1583
|
+
children: row.sessionId
|
|
1584
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
1585
|
+
className: button_module_css_default.dspPillRowPhase,
|
|
1586
|
+
children: t(row.phaseKey)
|
|
1587
|
+
})]
|
|
1588
|
+
}),
|
|
1589
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
1590
|
+
className: button_module_css_default.dspPillRowFacts,
|
|
1591
|
+
children: [row.readable ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("span", { children: [
|
|
1592
|
+
t("triage.stopped"),
|
|
1593
|
+
": ",
|
|
1594
|
+
row.stopped ?? "-"
|
|
1595
|
+
] }), (0, react_jsx_runtime.jsx)("span", { children: row.unknownTools.length === 0 ? t("triage.toolsNone") : `${t("triage.tools")}: ${row.unknownTools.join(", ")}` })] }) : (0, react_jsx_runtime.jsx)("span", { children: t("triage.stoppedUnknown") }), row.readable && !row.wakeable ? (0, react_jsx_runtime.jsx)("span", { children: t("triage.noWake") }) : null]
|
|
1596
|
+
}),
|
|
1597
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
1598
|
+
className: button_module_css_default.dspPillRowActions,
|
|
1599
|
+
children: [triageActionsFor(row).map((action) => (0, react_jsx_runtime.jsx)("button", {
|
|
1600
|
+
type: "button",
|
|
1601
|
+
className: button_module_css_default.dspPillAction,
|
|
1602
|
+
"aria-label": t(action.ariaKey),
|
|
1603
|
+
onClick: () => {
|
|
1604
|
+
decide(row.sessionId, action.action);
|
|
1605
|
+
},
|
|
1606
|
+
children: t(action.labelKey)
|
|
1607
|
+
}, action.action)), (0, react_jsx_runtime.jsx)("button", {
|
|
1608
|
+
type: "button",
|
|
1609
|
+
className: button_module_css_default.dspPillAction,
|
|
1610
|
+
"aria-label": t(TRIAGE_GOAL_VIEW.ariaKey),
|
|
1611
|
+
"aria-pressed": row.rearmGoal,
|
|
1612
|
+
onClick: () => {
|
|
1613
|
+
decide(row.sessionId, TRIAGE_GOAL_VIEW.action);
|
|
1614
|
+
},
|
|
1615
|
+
children: t(TRIAGE_GOAL_VIEW.labelKey)
|
|
1616
|
+
})]
|
|
1617
|
+
})
|
|
1618
|
+
]
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1621
|
+
/**
|
|
1622
|
+
* The whole-app control: what the host says about the whole park, the one
|
|
1623
|
+
* press that parks or releases all of it, and the decision list for whatever
|
|
1624
|
+
* did not stop cleanly.
|
|
1625
|
+
* @param props - session-header runtime, host operations, and localized copy.
|
|
1626
|
+
* @returns the control and its panel, or nothing while the host has not answered.
|
|
1627
|
+
*/
|
|
1628
|
+
function PausePill(props) {
|
|
1629
|
+
const { refresh, toggle, setPanel, decide, t, useSessions, useSession } = props;
|
|
1630
|
+
const reading = props.usePauseGlobal((state) => state.global);
|
|
1631
|
+
const triage = props.usePauseGlobal((state) => state.triage);
|
|
1632
|
+
const open = props.usePauseGlobal((state) => state.panelOpen);
|
|
1633
|
+
props.usePauseGlobal((state) => state.error);
|
|
1634
|
+
const sessions = props.usePauseGlobal((state) => state.sessions);
|
|
1635
|
+
const address = useSessions(addressingSession);
|
|
1636
|
+
const view = globalPauseView(reading, sessions);
|
|
1637
|
+
const list = triageView(triage);
|
|
1638
|
+
const visible = showsPauseControl(useSession((snapshot) => snapshot.subagent));
|
|
1639
|
+
(0, react.useEffect)(() => {
|
|
1640
|
+
if (visible && address !== void 0) refresh(address);
|
|
1641
|
+
}, [
|
|
1642
|
+
refresh,
|
|
1643
|
+
address,
|
|
1644
|
+
visible
|
|
1645
|
+
]);
|
|
1646
|
+
if (!visible || !view.visible || address === void 0) return null;
|
|
1647
|
+
const tip = view.caveats.map((caveat) => caveat.names.length === 0 ? t(caveat.key) : `${t(caveat.key)} (${caveat.names.join(", ")})`).join("\n");
|
|
1648
|
+
return (0, react_jsx_runtime.jsxs)("span", {
|
|
1649
|
+
className: button_module_css_default.dspPill,
|
|
1650
|
+
children: [
|
|
1651
|
+
!open ? null : (0, react_jsx_runtime.jsxs)("div", {
|
|
1652
|
+
className: button_module_css_default.dspPillPanel,
|
|
1653
|
+
role: "dialog",
|
|
1654
|
+
"aria-label": t("triage.title"),
|
|
1655
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
1656
|
+
className: button_module_css_default.dspPillPanelHead,
|
|
1657
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
1658
|
+
className: button_module_css_default.dspPillText,
|
|
1659
|
+
children: t("triage.title")
|
|
1660
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
1661
|
+
type: "button",
|
|
1662
|
+
className: button_module_css_default.dspPillAction,
|
|
1663
|
+
"aria-label": t("triage.refresh.aria"),
|
|
1664
|
+
onClick: () => {
|
|
1665
|
+
setPanel(true);
|
|
1666
|
+
},
|
|
1667
|
+
children: t("triage.refresh.aria")
|
|
1668
|
+
})]
|
|
1669
|
+
}), !list.visible ? (0, react_jsx_runtime.jsx)("p", {
|
|
1670
|
+
className: button_module_css_default.dspPillPanelNote,
|
|
1671
|
+
children: t("triage.reading")
|
|
1672
|
+
}) : list.unavailable ? (0, react_jsx_runtime.jsx)("p", {
|
|
1673
|
+
className: button_module_css_default.dspPillPanelNote,
|
|
1674
|
+
children: t("triage.unavailable")
|
|
1675
|
+
}) : list.rows.length === 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
1676
|
+
className: button_module_css_default.dspPillPanelNote,
|
|
1677
|
+
children: t("triage.empty")
|
|
1678
|
+
}) : (0, react_jsx_runtime.jsx)("ul", {
|
|
1679
|
+
className: button_module_css_default.dspPillRows,
|
|
1680
|
+
children: list.rows.map((row) => (0, react_jsx_runtime.jsx)(TriageSessionRow, {
|
|
1681
|
+
row,
|
|
1682
|
+
decide,
|
|
1683
|
+
t
|
|
1684
|
+
}, row.sessionId))
|
|
1685
|
+
})]
|
|
1686
|
+
}),
|
|
1687
|
+
view.unclean === 0 ? null : (0, react_jsx_runtime.jsxs)("button", {
|
|
1688
|
+
type: "button",
|
|
1689
|
+
className: button_module_css_default.dspPillTriage,
|
|
1690
|
+
"aria-label": t("triage.open.aria"),
|
|
1691
|
+
"aria-expanded": open,
|
|
1692
|
+
title: `${String(view.unclean)} ${t("all.triage")}`,
|
|
1693
|
+
onClick: () => {
|
|
1694
|
+
setPanel(!open);
|
|
1695
|
+
},
|
|
1696
|
+
children: [(0, react_jsx_runtime.jsx)(ChevronIcon, {}), (0, react_jsx_runtime.jsx)("span", {
|
|
1697
|
+
className: button_module_css_default.dspPillDetail,
|
|
1698
|
+
children: view.unclean
|
|
1699
|
+
})]
|
|
1700
|
+
}),
|
|
1701
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
1702
|
+
type: "button",
|
|
1703
|
+
className: view.labelKey === void 0 && view.detail.length === 0 ? `${button_module_css_default.dspPillBtn} ${button_module_css_default.dspPillIcon}` : button_module_css_default.dspPillBtn,
|
|
1704
|
+
"aria-label": t(view.ariaKey),
|
|
1705
|
+
"aria-pressed": view.action === "resume-all" || view.action === "cancel-all",
|
|
1706
|
+
disabled: !view.enabled,
|
|
1707
|
+
...tip.length === 0 ? {} : { title: tip },
|
|
1708
|
+
onClick: () => {
|
|
1709
|
+
toggle(address);
|
|
1710
|
+
},
|
|
1711
|
+
children: [
|
|
1712
|
+
view.action === "resume-all" || view.action === "cancel-all" ? (0, react_jsx_runtime.jsx)(ResumeIcon, {}) : (0, react_jsx_runtime.jsx)(PauseIcon, {}),
|
|
1713
|
+
view.labelKey === void 0 ? null : (0, react_jsx_runtime.jsx)("span", {
|
|
1714
|
+
className: button_module_css_default.dspPillText,
|
|
1715
|
+
children: t(view.labelKey)
|
|
1716
|
+
}),
|
|
1717
|
+
view.detail.length === 0 ? null : (0, react_jsx_runtime.jsx)("span", {
|
|
1718
|
+
className: button_module_css_default.dspPillDetail,
|
|
1719
|
+
children: view.detail
|
|
1720
|
+
}),
|
|
1721
|
+
view.caveats.length === 0 ? null : (0, react_jsx_runtime.jsx)("span", {
|
|
1722
|
+
className: button_module_css_default.dspPillWarn,
|
|
1723
|
+
children: (0, react_jsx_runtime.jsx)(CaveatIcon, {})
|
|
1724
|
+
})
|
|
1725
|
+
]
|
|
1726
|
+
})
|
|
1727
|
+
]
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
//#endregion
|
|
1731
|
+
//#region lib/types/client/locales.js
|
|
1732
|
+
/** `pause` namespace dictionaries. */
|
|
1733
|
+
/** Simplified Chinese dictionary (the key-set source of truth). */
|
|
1734
|
+
const zh = {
|
|
1735
|
+
"pause.aria": "暂停这个会话及其子代理:下一条模型请求不会发出",
|
|
1736
|
+
"resume.tip": "恢复这个会话及其子代理",
|
|
1737
|
+
"draining.aria": "正在暂停:还有工具在运行,工具运行完之后、下一条模型请求发出之前,会话会停住;按下可取消这次暂停",
|
|
1738
|
+
"parking.aria": "正在暂停:正在保存待发输入;按下可取消这次暂停",
|
|
1739
|
+
"safe.aria": "已暂停:待发输入已保存;按下可恢复",
|
|
1740
|
+
"flushFailed.aria": "已暂停,但保存待发输入失败;按下可恢复",
|
|
1741
|
+
"state.draining": "正在暂停",
|
|
1742
|
+
"state.parking": "正在保存",
|
|
1743
|
+
"state.safe": "已暂停",
|
|
1744
|
+
"state.flushFailed": "保存失败",
|
|
1745
|
+
"goal.aria": "恢复时重开目标:恢复这个会话时是否重新打开目标并让它继续运行;按下切换",
|
|
1746
|
+
"goal.on.tip": "恢复这个会话会重新打开目标,它会自己继续运行;按下改为不重开",
|
|
1747
|
+
"goal.off.tip": "恢复这个会话不会重新打开目标;按下改为重开",
|
|
1748
|
+
"checking.aria": "正在读取暂停状态",
|
|
1749
|
+
"checking.tip": "正在读取暂停状态",
|
|
1750
|
+
"unavailable.aria": "暂停状态不可用",
|
|
1751
|
+
"unavailable.tip": "暂停状态不可用",
|
|
1752
|
+
"all.pause.aria": "暂停所有运行中的会话及其子代理",
|
|
1753
|
+
"all.resume.aria": "恢复所有已暂停的会话",
|
|
1754
|
+
"all.idle": "暂停所有会话",
|
|
1755
|
+
"all.finishing": "正在暂停",
|
|
1756
|
+
"all.cancel": "取消这次暂停",
|
|
1757
|
+
"all.cancel.aria": "取消这次暂停并恢复会话",
|
|
1758
|
+
"all.unclean": "有会话未暂停",
|
|
1759
|
+
"all.unclean.aria": "有会话未暂停,不能在这里恢复;打开清单逐行处理",
|
|
1760
|
+
"all.safe": "已暂停",
|
|
1761
|
+
"all.checking.aria": "正在读取暂停状态",
|
|
1762
|
+
"all.caveat.jobs": "后台任务仍在运行",
|
|
1763
|
+
"all.caveat.unresumable": "含无法恢复的子代理",
|
|
1764
|
+
"all.caveat.stalled": "未暂停,需要你决定",
|
|
1765
|
+
"all.caveat.unread": "子代理列表读不出来",
|
|
1766
|
+
"all.caveat.blindTrees": "子代理服务未加载,无法检查子代理",
|
|
1767
|
+
"all.caveat.blindJobs": "作业服务未加载,无法检查后台任务",
|
|
1768
|
+
"triage.open.aria": "查看未暂停的会话清单",
|
|
1769
|
+
"triage.title": "未暂停的会话",
|
|
1770
|
+
"triage.empty": "没有需要决定的会话",
|
|
1771
|
+
"triage.reading": "正在读取清单",
|
|
1772
|
+
"triage.unavailable": "清单暂不可读",
|
|
1773
|
+
"triage.refresh.aria": "重新读取清单",
|
|
1774
|
+
"triage.session.aria": "会话",
|
|
1775
|
+
"triage.stopped": "停在",
|
|
1776
|
+
"triage.stoppedUnknown": "读不到它的日志,停止位置未知",
|
|
1777
|
+
"triage.tools": "未知的工具结果",
|
|
1778
|
+
"triage.toolsNone": "没有缺少结果的工具调用",
|
|
1779
|
+
"triage.noWake": "这个会话没有待发的模型请求,继续不会发出请求",
|
|
1780
|
+
"triage.phase.draining": "工具还在运行时中断",
|
|
1781
|
+
"triage.phase.parking": "已暂停,但待发输入未保存",
|
|
1782
|
+
"triage.phase.flushFailed": "已暂停,但保存失败",
|
|
1783
|
+
"triage.continue": "继续",
|
|
1784
|
+
"triage.continue.aria": "继续:不添加消息,直接恢复",
|
|
1785
|
+
"triage.note": "继续并附说明",
|
|
1786
|
+
"triage.note.aria": "继续并附说明:告诉模型工具结果未知,不要盲目重试",
|
|
1787
|
+
"triage.review": "只看不运行",
|
|
1788
|
+
"triage.review.aria": "只看不运行:不启动会话、不发请求;需要查看时在会话历史里打开",
|
|
1789
|
+
"triage.leave": "保持暂停",
|
|
1790
|
+
"triage.leave.aria": "保持暂停:不恢复,也不写入任何内容",
|
|
1791
|
+
"triage.goal": "恢复时重开目标",
|
|
1792
|
+
"triage.goal.aria": "恢复时重开目标:恢复这个会话时是否重新打开目标并让它自己继续运行;按下切换",
|
|
1793
|
+
"all.triage": "有待决定的会话"
|
|
1794
|
+
};
|
|
1795
|
+
/** English dictionary, checked complete against the zh key set. */
|
|
1796
|
+
const en = {
|
|
1797
|
+
"pause.aria": "Pause this session and its subagents: their next model request will not be sent",
|
|
1798
|
+
"resume.tip": "Resume this session and its subagents",
|
|
1799
|
+
"draining.aria": "Pausing: a tool is still running. The session pauses after the tool finishes and before its next model request; press to cancel the pause",
|
|
1800
|
+
"parking.aria": "Pausing: saving pending input; press to cancel the pause",
|
|
1801
|
+
"safe.aria": "Paused: pending input is saved; press to resume",
|
|
1802
|
+
"flushFailed.aria": "Paused, but saving pending input failed; press to resume",
|
|
1803
|
+
"state.draining": "Pausing",
|
|
1804
|
+
"state.parking": "Saving",
|
|
1805
|
+
"state.safe": "Paused",
|
|
1806
|
+
"state.flushFailed": "Save failed",
|
|
1807
|
+
"goal.aria": "Re-open goal on resume: whether resuming this session re-opens its goal and lets it run on its own; press to switch",
|
|
1808
|
+
"goal.on.tip": "Resuming re-opens the goal, which runs on its own; press to keep it closed",
|
|
1809
|
+
"goal.off.tip": "Resuming will not re-open the goal; press to re-open it",
|
|
1810
|
+
"checking.aria": "Reading pause state",
|
|
1811
|
+
"checking.tip": "Reading pause state",
|
|
1812
|
+
"unavailable.aria": "Pause state unavailable",
|
|
1813
|
+
"unavailable.tip": "Pause state unavailable",
|
|
1814
|
+
"all.pause.aria": "Pause all running sessions and their subagents",
|
|
1815
|
+
"all.resume.aria": "Resume all paused sessions",
|
|
1816
|
+
"all.idle": "Pause all sessions",
|
|
1817
|
+
"all.finishing": "Pausing",
|
|
1818
|
+
"all.cancel": "Cancel this pause",
|
|
1819
|
+
"all.cancel.aria": "Cancel this pause and resume the sessions",
|
|
1820
|
+
"all.unclean": "Some sessions are not paused",
|
|
1821
|
+
"all.unclean.aria": "Some sessions are not paused and cannot be resumed here; open the list to decide",
|
|
1822
|
+
"all.safe": "Paused",
|
|
1823
|
+
"all.checking.aria": "Reading pause state",
|
|
1824
|
+
"all.caveat.jobs": "background jobs are still running",
|
|
1825
|
+
"all.caveat.unresumable": "contains a subagent that cannot be resumed",
|
|
1826
|
+
"all.caveat.stalled": "did not pause; needs your decision",
|
|
1827
|
+
"all.caveat.unread": "subagent list could not be read",
|
|
1828
|
+
"all.caveat.blindTrees": "subagent service is not loaded, so subagents cannot be checked",
|
|
1829
|
+
"all.caveat.blindJobs": "job service is not loaded, so background jobs cannot be checked",
|
|
1830
|
+
"triage.open.aria": "Review sessions that did not pause",
|
|
1831
|
+
"triage.title": "Sessions that did not pause",
|
|
1832
|
+
"triage.empty": "No sessions need a decision",
|
|
1833
|
+
"triage.reading": "Reading list",
|
|
1834
|
+
"triage.unavailable": "List unavailable",
|
|
1835
|
+
"triage.refresh.aria": "Read the list again",
|
|
1836
|
+
"triage.session.aria": "Session",
|
|
1837
|
+
"triage.stopped": "Stopped at",
|
|
1838
|
+
"triage.stoppedUnknown": "Its log cannot be read, so where it stopped is unknown",
|
|
1839
|
+
"triage.tools": "Unknown tool results",
|
|
1840
|
+
"triage.toolsNone": "No tool call is missing a result",
|
|
1841
|
+
"triage.noWake": "This session has no pending model request; continuing sends nothing",
|
|
1842
|
+
"triage.phase.draining": "stopped while a tool was still running",
|
|
1843
|
+
"triage.phase.parking": "paused but pending input was not saved",
|
|
1844
|
+
"triage.phase.flushFailed": "paused but saving failed",
|
|
1845
|
+
"triage.continue": "Continue",
|
|
1846
|
+
"triage.continue.aria": "Continue: resume without adding a message",
|
|
1847
|
+
"triage.note": "Continue with a note",
|
|
1848
|
+
"triage.note.aria": "Continue with a note: tell the model the tool result is unknown and not to retry blindly",
|
|
1849
|
+
"triage.review": "View only",
|
|
1850
|
+
"triage.review.aria": "View only: do not start the session or send a request; open it from your session history to read it",
|
|
1851
|
+
"triage.leave": "Leave it paused",
|
|
1852
|
+
"triage.leave.aria": "Leave it paused: keep the pause and write nothing",
|
|
1853
|
+
"triage.goal": "Re-open goal on resume",
|
|
1854
|
+
"triage.goal.aria": "Re-open goal on resume: whether resuming this session re-opens its goal, which then runs on its own; press to switch",
|
|
1855
|
+
"all.triage": "sessions need a decision"
|
|
1856
|
+
};
|
|
1857
|
+
//#endregion
|
|
1858
|
+
//#region lib/types/client/index.js
|
|
1859
|
+
/**
|
|
1860
|
+
* Browser half of dsh-pause-session.
|
|
1861
|
+
*
|
|
1862
|
+
* Registers two controls: one in the session header's title-adjacent action
|
|
1863
|
+
* group (`conversation.session.header.actions`), which pauses or resumes the
|
|
1864
|
+
* session it sits on, and one in the header's right-aligned utilities row
|
|
1865
|
+
* (`conversation.session.header.utilities`), which answers for the whole app.
|
|
1866
|
+
* Both seats are session-scoped and their props carry `sessionId`, so every
|
|
1867
|
+
* open session header renders its own pair and switching sessions follows
|
|
1868
|
+
* automatically; the whole-app control speaks for every session from the
|
|
1869
|
+
* header of the one on screen.
|
|
1870
|
+
*
|
|
1871
|
+
* The whole-app control sits inside the conversation column rather than in the
|
|
1872
|
+
* frame-wide overlay layer: it is read while looking at one conversation, and
|
|
1873
|
+
* a sidebar or drawer that covers that area covers the control with it.
|
|
1874
|
+
*
|
|
1875
|
+
* Both controls are host-authoritative. On a browser Host they read the
|
|
1876
|
+
* native `pauseSession` stream, which keeps status reads out of the Session
|
|
1877
|
+
* log. The same path serves Web and Desktop.
|
|
1878
|
+
* User actions and status both use the generated native Remote namespace;
|
|
1879
|
+
* no slash command is involved. Each control stays inert wherever no
|
|
1880
|
+
* round-trip is available rather than rendering a state it cannot support. The
|
|
1881
|
+
* header control also reads the whole-app answer the whole-app control
|
|
1882
|
+
* publishes, so a park that holds nothing does not cost a host round-trip per
|
|
1883
|
+
* header.
|
|
1884
|
+
* @module dsh-pause-session/client
|
|
1885
|
+
*/
|
|
1886
|
+
/** Dictionary namespace owned by this plugin. */
|
|
1887
|
+
const NS = "pause";
|
|
1888
|
+
/** Required services: the slot registry, the locale registry, and the host round-trip. */
|
|
1889
|
+
const inject = [
|
|
1890
|
+
"slots",
|
|
1891
|
+
"locale",
|
|
1892
|
+
"remote"
|
|
1893
|
+
];
|
|
1894
|
+
/**
|
|
1895
|
+
* The session's pause control: pause the session and its subagents before
|
|
1896
|
+
* their next model request, or resume them, with the host's own state on screen.
|
|
1897
|
+
* Once the host reports the park's goal opt-out, a second switch sits beside it
|
|
1898
|
+
* — the only place a session that stopped CLEANLY can be told not to re-open its
|
|
1899
|
+
* goal on the next resume, because the decision list shows only the sessions
|
|
1900
|
+
* that did not stop cleanly.
|
|
1901
|
+
*
|
|
1902
|
+
* A subagent session renders nothing: its work is its parent's, the parent's
|
|
1903
|
+
* control already covers it, and a button here would offer to pause "a session"
|
|
1904
|
+
* from inside a child.
|
|
1905
|
+
* @param props - session runtime, host operations, and localized copy.
|
|
1906
|
+
* @returns the header action, or nothing on a subagent session.
|
|
1907
|
+
*/
|
|
1908
|
+
function PauseButton(props) {
|
|
1909
|
+
const { sessionId, refresh, toggle, toggleGoal, t, useSession } = props;
|
|
1910
|
+
const view = pauseView(props.usePause((state) => state.bySession[String(sessionId)]), useSession((snapshot) => snapshot.running) ?? false);
|
|
1911
|
+
const visible = showsPauseControl(useSession((snapshot) => snapshot.subagent));
|
|
1912
|
+
(0, react.useEffect)(() => {
|
|
1913
|
+
refresh(sessionId);
|
|
1914
|
+
}, [refresh, sessionId]);
|
|
1915
|
+
if (!visible) return null;
|
|
1916
|
+
return (0, react_jsx_runtime.jsxs)("span", {
|
|
1917
|
+
className: button_module_css_default.dsp,
|
|
1918
|
+
children: [
|
|
1919
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
1920
|
+
type: "button",
|
|
1921
|
+
className: button_module_css_default.dspBtn,
|
|
1922
|
+
"aria-label": t(view.ariaKey),
|
|
1923
|
+
"aria-pressed": view.paused,
|
|
1924
|
+
disabled: !view.enabled,
|
|
1925
|
+
onClick: () => {
|
|
1926
|
+
toggle(sessionId);
|
|
1927
|
+
},
|
|
1928
|
+
children: view.paused ? (0, react_jsx_runtime.jsx)(ResumeIcon, {}) : (0, react_jsx_runtime.jsx)(PauseIcon, {})
|
|
1929
|
+
}),
|
|
1930
|
+
view.rearmGoal === void 0 ? null : (0, react_jsx_runtime.jsx)("button", {
|
|
1931
|
+
type: "button",
|
|
1932
|
+
className: button_module_css_default.dspGoal,
|
|
1933
|
+
"aria-label": t("goal.aria"),
|
|
1934
|
+
"aria-pressed": view.rearmGoal,
|
|
1935
|
+
title: t(view.rearmGoal ? "goal.on.tip" : "goal.off.tip"),
|
|
1936
|
+
onClick: () => {
|
|
1937
|
+
toggleGoal(sessionId);
|
|
1938
|
+
},
|
|
1939
|
+
children: (0, react_jsx_runtime.jsx)(GoalIcon, {})
|
|
1940
|
+
}),
|
|
1941
|
+
view.labelKey === void 0 ? null : (0, react_jsx_runtime.jsxs)("span", {
|
|
1942
|
+
className: button_module_css_default.dspState,
|
|
1943
|
+
children: [t(view.labelKey), view.runningTools.length === 0 ? null : `: ${view.runningTools.join(", ")}`]
|
|
1944
|
+
})
|
|
1945
|
+
]
|
|
1946
|
+
});
|
|
1947
|
+
}
|
|
1948
|
+
/**
|
|
1949
|
+
* Client plugin body: register the locale dictionaries, own both controllers,
|
|
1950
|
+
* follow the host's registry changes, and contribute the per-session control
|
|
1951
|
+
* and the whole-app control into the session header.
|
|
1952
|
+
* @param ctx - client context carrying slots, locale, and the Remote face.
|
|
1953
|
+
*/
|
|
1954
|
+
function apply(ctx) {
|
|
1955
|
+
ctx.effect(() => ctx.locale.register(NS, {
|
|
1956
|
+
zh,
|
|
1957
|
+
en
|
|
1958
|
+
}), "pause: dictionaries");
|
|
1959
|
+
const lifetime = new AbortController();
|
|
1960
|
+
ctx.effect(() => () => {
|
|
1961
|
+
lifetime.abort(/* @__PURE__ */ new Error("pause: client unloaded"));
|
|
1962
|
+
}, "pause: lifetime");
|
|
1963
|
+
if (typeof ctx.remote.$mount === "function") ctx.effect(async () => {
|
|
1964
|
+
return await ctx.remote.$mount(TYPERT_REMOTE);
|
|
1965
|
+
}, "pause: remote transport");
|
|
1966
|
+
ctx.inject(["remote.pauseSession"], (remoteCtx) => {
|
|
1967
|
+
const remote = remoteCtx.remote.pauseSession;
|
|
1968
|
+
const transport = remoteTransport(remote, lifetime.signal);
|
|
1969
|
+
const globalControl = new PauseGlobalControl(transport, lifetime.signal);
|
|
1970
|
+
const control = new PauseControl(transport, lifetime.signal);
|
|
1971
|
+
remoteCtx.effect(() => transport.source.onSnapshot((snapshot) => {
|
|
1972
|
+
control.apply(snapshot);
|
|
1973
|
+
globalControl.apply(snapshot);
|
|
1974
|
+
}), "pause: native status stream");
|
|
1975
|
+
remoteCtx.slots.inject("conversation.session.header.actions", () => remoteCtx.slots.register({
|
|
1976
|
+
name: "conversation.session.header.actions",
|
|
1977
|
+
id: NS,
|
|
1978
|
+
order: 40,
|
|
1979
|
+
locale: NS,
|
|
1980
|
+
inject: () => ({
|
|
1981
|
+
hooks: { pause: control.store },
|
|
1982
|
+
refresh: (sessionId) => {
|
|
1983
|
+
control.refresh(sessionId);
|
|
1984
|
+
},
|
|
1985
|
+
toggle: (sessionId) => {
|
|
1986
|
+
control.toggle(sessionId);
|
|
1987
|
+
},
|
|
1988
|
+
toggleGoal: (sessionId) => {
|
|
1989
|
+
control.toggleGoal(sessionId);
|
|
1990
|
+
}
|
|
1991
|
+
})
|
|
1992
|
+
}, PauseButton));
|
|
1993
|
+
remoteCtx.slots.inject("conversation.session.header.utilities", () => remoteCtx.slots.register({
|
|
1994
|
+
name: "conversation.session.header.utilities",
|
|
1995
|
+
id: "pause-all",
|
|
1996
|
+
order: -11,
|
|
1997
|
+
locale: NS,
|
|
1998
|
+
inject: () => ({
|
|
1999
|
+
hooks: { pauseGlobal: globalControl.store },
|
|
2000
|
+
refresh: (sessionId) => {
|
|
2001
|
+
globalControl.refresh(sessionId);
|
|
2002
|
+
},
|
|
2003
|
+
toggle: (sessionId) => {
|
|
2004
|
+
globalControl.toggle(sessionId);
|
|
2005
|
+
},
|
|
2006
|
+
setPanel: (open) => {
|
|
2007
|
+
globalControl.setPanel(open);
|
|
2008
|
+
},
|
|
2009
|
+
decide: (sessionId, action) => {
|
|
2010
|
+
globalControl.decide(sessionId, action);
|
|
2011
|
+
}
|
|
2012
|
+
})
|
|
2013
|
+
}, PausePill));
|
|
2014
|
+
});
|
|
2015
|
+
}
|
|
2016
|
+
//#endregion
|
|
2017
|
+
exports.PauseButton = PauseButton;
|
|
2018
|
+
exports.apply = apply;
|
|
2019
|
+
exports.inject = inject;
|
|
2020
|
+
return module.exports;
|
|
2021
|
+
}
|
|
2022
|
+
});
|
|
2023
|
+
|
|
2024
|
+
//# sourceMappingURL=client.js.map
|