dsh-rewind-plugin 0.18.0 → 0.19.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/README.en.md +6 -14
- package/README.md +5 -10
- package/lib/client.js +494 -338
- package/lib/index.js +2 -2
- package/lib/types/client/candidates.d.ts +4 -6
- package/lib/types/client/hidden.d.ts +30 -36
- package/lib/types/client/index.d.ts +1 -7
- package/lib/types/client/portals.d.ts +3 -65
- package/lib/types/client/styles.d.ts +1 -1
- package/lib/types/client/visibility.d.ts +89 -0
- package/lib/types/index.d.ts +2 -2
- package/lib/types/rewind.d.ts +7 -7
- package/package.json +37 -37
package/lib/client.js
CHANGED
|
@@ -9,6 +9,7 @@ var __defProp = Object.defineProperty;
|
|
|
9
9
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
10
10
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
11
11
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
12
13
|
var __export = (target, all) => {
|
|
13
14
|
for (var name2 in all)
|
|
14
15
|
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
@@ -22,22 +23,72 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
22
23
|
return to;
|
|
23
24
|
};
|
|
24
25
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
26
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
25
27
|
|
|
26
28
|
// src/client/index.ts
|
|
27
29
|
var index_exports = {};
|
|
28
30
|
__export(index_exports, {
|
|
29
31
|
apply: () => apply,
|
|
30
|
-
hiddenSeqsOf: () => hiddenSeqsOf,
|
|
31
32
|
inject: () => inject,
|
|
32
|
-
name: () => name
|
|
33
|
-
targetSeqOfArgs: () => targetSeqOfArgs
|
|
33
|
+
name: () => name
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
|
+
// src/client/candidates.ts
|
|
38
|
+
var PREVIEW_CHARS = 80;
|
|
39
|
+
var DEFAULT_CANDIDATE_LIMIT = 100;
|
|
40
|
+
function messagePreviewOf(message) {
|
|
41
|
+
const text = message.content.map((block) => block.type === "text" && typeof block.text === "string" ? block.text : "").join("").replace(/\s+/g, " ").trim();
|
|
42
|
+
return text.length <= PREVIEW_CHARS ? text : `${text.slice(0, PREVIEW_CHARS - 1)}\u2026`;
|
|
43
|
+
}
|
|
44
|
+
function formatCandidateTime(time) {
|
|
45
|
+
const d = new Date(time);
|
|
46
|
+
const hh = String(d.getHours()).padStart(2, "0");
|
|
47
|
+
const mm = String(d.getMinutes()).padStart(2, "0");
|
|
48
|
+
return `${hh}:${mm}`;
|
|
49
|
+
}
|
|
50
|
+
function rewindCandidatesOf(snap, limit = DEFAULT_CANDIDATE_LIMIT) {
|
|
51
|
+
const candidates = [];
|
|
52
|
+
for (let i = snap.order.length - 1; i >= 0 && candidates.length < limit; i--) {
|
|
53
|
+
const key = snap.order[i];
|
|
54
|
+
if (key === void 0) continue;
|
|
55
|
+
const node = snap.nodes.get(key);
|
|
56
|
+
if (node === void 0 || node.kind !== "user" && node.kind !== "steering") continue;
|
|
57
|
+
candidates.push({
|
|
58
|
+
seq: node.data.seq,
|
|
59
|
+
time: node.data.time,
|
|
60
|
+
preview: messagePreviewOf(node.data)
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return candidates;
|
|
64
|
+
}
|
|
65
|
+
function rewindCandidatesOfChat(snap) {
|
|
66
|
+
return rewindCandidatesOf(snap);
|
|
67
|
+
}
|
|
68
|
+
function rewindOptionsFromCandidates(candidates, t) {
|
|
69
|
+
return candidates.map((candidate) => ({
|
|
70
|
+
id: String(candidate.seq),
|
|
71
|
+
label: candidate.preview || t("popover.noText"),
|
|
72
|
+
detail: formatCandidateTime(candidate.time)
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
|
|
37
76
|
// src/client/hidden.ts
|
|
38
77
|
var ENGINE_COMMAND = "rewind-plugin";
|
|
39
78
|
var LEGACY_ENGINE_COMMAND = "rewind";
|
|
40
79
|
var ENGINE_COMMANDS = /* @__PURE__ */ new Set([ENGINE_COMMAND, LEGACY_ENGINE_COMMAND]);
|
|
80
|
+
function chatNodesOf(chat) {
|
|
81
|
+
if (chat === void 0) return EMPTY_NODES;
|
|
82
|
+
const values = chat.nodes.values;
|
|
83
|
+
if (typeof values === "function") return [...values.call(chat.nodes)];
|
|
84
|
+
const nodes = [];
|
|
85
|
+
for (const key of chat.order) {
|
|
86
|
+
const node = chat.nodes.get(key);
|
|
87
|
+
if (node !== void 0) nodes.push(node);
|
|
88
|
+
}
|
|
89
|
+
return nodes;
|
|
90
|
+
}
|
|
91
|
+
var EMPTY_NODES = [];
|
|
41
92
|
function resolveChatWatch(resolveView, sessionId, cb) {
|
|
42
93
|
const view = resolveView(sessionId);
|
|
43
94
|
return view?.subscribe?.(cb) ?? (() => {
|
|
@@ -48,9 +99,8 @@ function chatSnapshotOf(chatView) {
|
|
|
48
99
|
}
|
|
49
100
|
function messageTextAt(chat, seq) {
|
|
50
101
|
if (chat === void 0) return void 0;
|
|
51
|
-
for (const
|
|
52
|
-
|
|
53
|
-
if (node === void 0 || node.kind !== "user" && node.kind !== "steering") continue;
|
|
102
|
+
for (const node of chatNodesOf(chat)) {
|
|
103
|
+
if (node.kind !== "user" && node.kind !== "steering") continue;
|
|
54
104
|
const data = node.data;
|
|
55
105
|
if (data.seq === seq) {
|
|
56
106
|
return data.content?.map((block) => block.type === "text" && typeof block.text === "string" ? block.text : "").join("");
|
|
@@ -60,9 +110,8 @@ function messageTextAt(chat, seq) {
|
|
|
60
110
|
}
|
|
61
111
|
function messageAttachmentsAt(chat, seq) {
|
|
62
112
|
if (chat === void 0) return void 0;
|
|
63
|
-
for (const
|
|
64
|
-
|
|
65
|
-
if (node === void 0 || node.kind !== "user" && node.kind !== "steering") continue;
|
|
113
|
+
for (const node of chatNodesOf(chat)) {
|
|
114
|
+
if (node.kind !== "user" && node.kind !== "steering") continue;
|
|
66
115
|
const data = node.data;
|
|
67
116
|
if (data.seq !== seq) continue;
|
|
68
117
|
const images = [];
|
|
@@ -100,141 +149,21 @@ function isPreviewCommand(command) {
|
|
|
100
149
|
function isCandidateCommand(command) {
|
|
101
150
|
return (command.args ?? "").includes("__candidates");
|
|
102
151
|
}
|
|
103
|
-
function
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
for (const span of sorted) {
|
|
108
|
-
const last = merged[merged.length - 1];
|
|
109
|
-
if (last !== void 0 && span.start <= last.end) {
|
|
110
|
-
if (span.end > last.end) last.end = span.end;
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
merged.push({ start: span.start, end: span.end });
|
|
114
|
-
}
|
|
115
|
-
return merged;
|
|
116
|
-
}
|
|
117
|
-
function cutsContain(cuts, seq) {
|
|
118
|
-
let low = 0;
|
|
119
|
-
let high = cuts.length - 1;
|
|
120
|
-
while (low <= high) {
|
|
121
|
-
const middle = low + high >> 1;
|
|
122
|
-
const cut = cuts[middle];
|
|
123
|
-
if (seq < cut.start) high = middle - 1;
|
|
124
|
-
else if (seq > cut.end) low = middle + 1;
|
|
125
|
-
else return true;
|
|
126
|
-
}
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
function liveAnchorKeys(snap, cuts) {
|
|
130
|
-
const live = /* @__PURE__ */ new Map();
|
|
131
|
-
for (const key of snap.order) {
|
|
132
|
-
const node = snap.nodes.get(key);
|
|
133
|
-
if (node === void 0 || cutsContain(cuts, node.anchorSeq)) continue;
|
|
134
|
-
const keys = live.get(node.anchorSeq);
|
|
135
|
-
if (keys === void 0) live.set(node.anchorSeq, [key]);
|
|
136
|
-
else keys.push(key);
|
|
137
|
-
}
|
|
138
|
-
return live;
|
|
139
|
-
}
|
|
140
|
-
var EMPTY_KEYS = [];
|
|
141
|
-
function addWithdrawnTurnChrome(snap, cuts, hidden) {
|
|
142
|
-
const locations = snap.locations;
|
|
143
|
-
if (locations === void 0 || cuts.length === 0) return;
|
|
144
|
-
let live;
|
|
145
|
-
for (const key of snap.order) {
|
|
146
|
-
const chrome = snap.nodes.get(key);
|
|
147
|
-
if (chrome === void 0 || chrome.kind !== "turn-process") continue;
|
|
148
|
-
const located = chrome.location?.turn;
|
|
149
|
-
if (located?.start === void 0) continue;
|
|
150
|
-
const turn = located.turn;
|
|
151
|
-
if (typeof turn !== "number") continue;
|
|
152
|
-
const keys = locations.getTurn(turn);
|
|
153
|
-
if (keys.length === 0) continue;
|
|
154
|
-
const rows = keys.map((member) => snap.nodes.get(member)).filter((member) => member !== void 0);
|
|
155
|
-
if (rows.length !== keys.length) continue;
|
|
156
|
-
if (!rows.every((member) => member.key === chrome.key || cutsContain(cuts, member.anchorSeq))) continue;
|
|
157
|
-
live ?? (live = liveAnchorKeys(snap, cuts));
|
|
158
|
-
if ((live.get(chrome.anchorSeq) ?? EMPTY_KEYS).some((holder) => holder !== chrome.key)) continue;
|
|
159
|
-
hidden.add(chrome.anchorSeq);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
var hiddenSeqsMemo = /* @__PURE__ */ new WeakMap();
|
|
163
|
-
function hiddenSeqsOf(snap) {
|
|
164
|
-
const memo = hiddenSeqsMemo.get(snap);
|
|
165
|
-
if (memo !== void 0) return new Set(memo);
|
|
166
|
-
const hidden = /* @__PURE__ */ new Set();
|
|
167
|
-
const spans = [];
|
|
168
|
-
for (const key of snap.order) {
|
|
169
|
-
const node = snap.nodes.get(key);
|
|
170
|
-
if (node === void 0 || node.kind !== "command") continue;
|
|
152
|
+
function rewindCutsOf(nodes) {
|
|
153
|
+
const cuts = [];
|
|
154
|
+
for (const node of nodes) {
|
|
155
|
+
if (node.kind !== "command") continue;
|
|
171
156
|
const command = node.data;
|
|
172
157
|
if (command.name === null || !ENGINE_COMMANDS.has(command.name)) continue;
|
|
173
|
-
if (isPreviewCommand(command) || isCandidateCommand(command))
|
|
174
|
-
hidden.add(command.seq);
|
|
175
|
-
continue;
|
|
176
|
-
}
|
|
158
|
+
if (isPreviewCommand(command) || isCandidateCommand(command)) continue;
|
|
177
159
|
if (command.outcome?.kind !== "success") continue;
|
|
178
160
|
const marker = command.outcome.sourceEventSeq;
|
|
179
161
|
if (marker === void 0) continue;
|
|
180
|
-
hidden.add(command.seq);
|
|
181
162
|
const target = targetSeqOfArgs(command.args);
|
|
182
|
-
if (target
|
|
183
|
-
|
|
184
|
-
}
|
|
163
|
+
if (target === void 0 || target > marker) continue;
|
|
164
|
+
cuts.push({ target, marker });
|
|
185
165
|
}
|
|
186
|
-
|
|
187
|
-
for (const key of snap.order) {
|
|
188
|
-
const node = snap.nodes.get(key);
|
|
189
|
-
if (node === void 0) continue;
|
|
190
|
-
if (cutsContain(cuts, node.anchorSeq)) hidden.add(node.anchorSeq);
|
|
191
|
-
}
|
|
192
|
-
try {
|
|
193
|
-
addWithdrawnTurnChrome(snap, cuts, hidden);
|
|
194
|
-
} catch {
|
|
195
|
-
}
|
|
196
|
-
hiddenSeqsMemo.set(snap, new Set(hidden));
|
|
197
|
-
return hidden;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// src/client/candidates.ts
|
|
201
|
-
var PREVIEW_CHARS = 80;
|
|
202
|
-
var DEFAULT_CANDIDATE_LIMIT = 100;
|
|
203
|
-
function messagePreviewOf(message) {
|
|
204
|
-
const text = message.content.map((block) => block.type === "text" && typeof block.text === "string" ? block.text : "").join("").replace(/\s+/g, " ").trim();
|
|
205
|
-
return text.length <= PREVIEW_CHARS ? text : `${text.slice(0, PREVIEW_CHARS - 1)}\u2026`;
|
|
206
|
-
}
|
|
207
|
-
function formatCandidateTime(time) {
|
|
208
|
-
const d = new Date(time);
|
|
209
|
-
const hh = String(d.getHours()).padStart(2, "0");
|
|
210
|
-
const mm = String(d.getMinutes()).padStart(2, "0");
|
|
211
|
-
return `${hh}:${mm}`;
|
|
212
|
-
}
|
|
213
|
-
function rewindCandidatesOf(snap, hidden, limit = DEFAULT_CANDIDATE_LIMIT) {
|
|
214
|
-
const candidates = [];
|
|
215
|
-
for (let i = snap.order.length - 1; i >= 0 && candidates.length < limit; i--) {
|
|
216
|
-
const key = snap.order[i];
|
|
217
|
-
if (key === void 0) continue;
|
|
218
|
-
const node = snap.nodes.get(key);
|
|
219
|
-
if (node === void 0 || node.kind !== "user" && node.kind !== "steering") continue;
|
|
220
|
-
if (hidden.has(node.anchorSeq ?? node.data.seq)) continue;
|
|
221
|
-
candidates.push({
|
|
222
|
-
seq: node.data.seq,
|
|
223
|
-
time: node.data.time,
|
|
224
|
-
preview: messagePreviewOf(node.data)
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
return candidates;
|
|
228
|
-
}
|
|
229
|
-
function rewindCandidatesOfChat(snap) {
|
|
230
|
-
return rewindCandidatesOf(snap, hiddenSeqsOf(snap));
|
|
231
|
-
}
|
|
232
|
-
function rewindOptionsFromCandidates(candidates, t) {
|
|
233
|
-
return candidates.map((candidate) => ({
|
|
234
|
-
id: String(candidate.seq),
|
|
235
|
-
label: candidate.preview || t("popover.noText"),
|
|
236
|
-
detail: formatCandidateTime(candidate.time)
|
|
237
|
-
}));
|
|
166
|
+
return cuts;
|
|
238
167
|
}
|
|
239
168
|
|
|
240
169
|
// src/client/styles.ts
|
|
@@ -278,47 +207,58 @@ var STYLE = `
|
|
|
278
207
|
width: calc(15px + var(--dsh-content-font-delta, 0px));
|
|
279
208
|
height: calc(15px + var(--dsh-content-font-delta, 0px));
|
|
280
209
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
210
|
+
@media (hover: hover) {
|
|
211
|
+
.dsh-rewind-btn:hover {
|
|
212
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
213
|
+
color: var(--dsw-alias-label-secondary);
|
|
214
|
+
}
|
|
284
215
|
}
|
|
285
216
|
|
|
286
217
|
.dsh-rewind-popover {
|
|
287
218
|
position: fixed;
|
|
288
|
-
z-index:
|
|
289
|
-
|
|
290
|
-
|
|
219
|
+
z-index: 1100;
|
|
220
|
+
box-sizing: border-box;
|
|
221
|
+
width: min(300px, calc(100vw - 24px));
|
|
222
|
+
padding: 16px;
|
|
291
223
|
border: 0;
|
|
292
|
-
border-radius: var(--dsw-radius-
|
|
224
|
+
border-radius: var(--dsw-radius-lg);
|
|
293
225
|
background: var(--dsw-specific-menu, var(--dsw-alias-bg-layer-3));
|
|
294
226
|
backdrop-filter: var(--dsw-menu-backdrop-filter);
|
|
295
227
|
isolation: isolate;
|
|
296
228
|
--dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
|
|
229
|
+
/* Elevated surface: match the menu cards' l2 scrollbar tokens. */
|
|
230
|
+
--dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
|
|
231
|
+
--dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
|
|
297
232
|
box-shadow: var(--dsw-elevation-prominent);
|
|
298
|
-
font-size:
|
|
299
|
-
line-height:
|
|
233
|
+
font-size: 12px;
|
|
234
|
+
line-height: 18px;
|
|
300
235
|
color: var(--dsw-alias-label-primary);
|
|
301
236
|
}
|
|
302
237
|
.dsh-rewind-popover-title {
|
|
303
|
-
font-size:
|
|
304
|
-
font-weight:
|
|
305
|
-
line-height:
|
|
238
|
+
font-size: 12px;
|
|
239
|
+
font-weight: 500;
|
|
240
|
+
line-height: 18px;
|
|
306
241
|
}
|
|
307
242
|
.dsh-rewind-popover-target {
|
|
308
|
-
margin:
|
|
243
|
+
margin: 2px 0 10px;
|
|
309
244
|
font-size: 12px;
|
|
310
|
-
line-height:
|
|
245
|
+
line-height: 18px;
|
|
311
246
|
color: var(--dsw-alias-label-tertiary);
|
|
312
247
|
word-break: break-all;
|
|
248
|
+
/* The full message sits above the popover; two lines are enough context. */
|
|
249
|
+
display: -webkit-box;
|
|
250
|
+
-webkit-box-orient: vertical;
|
|
251
|
+
-webkit-line-clamp: 2;
|
|
252
|
+
overflow: hidden;
|
|
313
253
|
}
|
|
314
254
|
.dsh-rewind-popover-option {
|
|
315
255
|
display: flex;
|
|
316
256
|
flex-direction: column;
|
|
317
257
|
gap: 2px;
|
|
318
258
|
width: 100%;
|
|
319
|
-
margin: 0 0
|
|
320
|
-
padding: 8px
|
|
321
|
-
border:
|
|
259
|
+
margin: 0 0 2px;
|
|
260
|
+
padding: 6px 8px;
|
|
261
|
+
border: 0;
|
|
322
262
|
border-radius: 8px;
|
|
323
263
|
background: transparent;
|
|
324
264
|
color: inherit;
|
|
@@ -338,7 +278,7 @@ var STYLE = `
|
|
|
338
278
|
outline: none;
|
|
339
279
|
}
|
|
340
280
|
.dsh-rewind-popover-option:disabled {
|
|
341
|
-
opacity: 0.
|
|
281
|
+
opacity: 0.4;
|
|
342
282
|
cursor: default;
|
|
343
283
|
}
|
|
344
284
|
.dsh-rewind-popover-option-label {
|
|
@@ -371,15 +311,15 @@ var STYLE = `
|
|
|
371
311
|
display: flex;
|
|
372
312
|
justify-content: flex-end;
|
|
373
313
|
gap: 8px;
|
|
314
|
+
margin-top: 8px;
|
|
374
315
|
}
|
|
375
316
|
.dsh-rewind-popover-primary,
|
|
376
317
|
.dsh-rewind-popover-ghost {
|
|
377
|
-
|
|
318
|
+
height: 28px;
|
|
319
|
+
padding: 0 10px;
|
|
378
320
|
border: none;
|
|
379
321
|
border-radius: 8px;
|
|
380
322
|
font: inherit;
|
|
381
|
-
font-size: 13px;
|
|
382
|
-
line-height: 18px;
|
|
383
323
|
cursor: pointer;
|
|
384
324
|
}
|
|
385
325
|
.dsh-rewind-popover-primary {
|
|
@@ -390,7 +330,7 @@ var STYLE = `
|
|
|
390
330
|
background: var(--dsw-alias-button-primary-hover);
|
|
391
331
|
}
|
|
392
332
|
.dsh-rewind-popover-primary:disabled {
|
|
393
|
-
opacity: 0.
|
|
333
|
+
opacity: 0.4;
|
|
394
334
|
cursor: default;
|
|
395
335
|
}
|
|
396
336
|
.dsh-rewind-popover-ghost {
|
|
@@ -400,6 +340,9 @@ var STYLE = `
|
|
|
400
340
|
.dsh-rewind-popover-ghost:hover {
|
|
401
341
|
background: var(--dsw-alias-interactive-bg-hover);
|
|
402
342
|
}
|
|
343
|
+
.dsh-rewind-popover-ghost:active {
|
|
344
|
+
background: var(--dsw-alias-interactive-bg-active);
|
|
345
|
+
}
|
|
403
346
|
|
|
404
347
|
.dsh-rewind-guard-hint {
|
|
405
348
|
position: fixed;
|
|
@@ -452,12 +395,21 @@ var STYLE = `
|
|
|
452
395
|
|
|
453
396
|
// src/client/popover.ts
|
|
454
397
|
var popoverEl = null;
|
|
398
|
+
var popoverAnchor = null;
|
|
455
399
|
var disposeOutside = null;
|
|
456
400
|
var liveSessionId = null;
|
|
457
401
|
var composerFocuser = null;
|
|
458
402
|
function registerComposerFocuser(focus) {
|
|
459
403
|
composerFocuser = focus;
|
|
460
404
|
}
|
|
405
|
+
function markOpen(anchor) {
|
|
406
|
+
popoverAnchor = anchor;
|
|
407
|
+
anchor.setAttribute("aria-expanded", "true");
|
|
408
|
+
}
|
|
409
|
+
function markClosed() {
|
|
410
|
+
popoverAnchor?.setAttribute("aria-expanded", "false");
|
|
411
|
+
popoverAnchor = null;
|
|
412
|
+
}
|
|
461
413
|
function closePopover() {
|
|
462
414
|
if (popoverEl !== null) {
|
|
463
415
|
popoverEl.remove();
|
|
@@ -467,6 +419,7 @@ function closePopover() {
|
|
|
467
419
|
disposeOutside();
|
|
468
420
|
disposeOutside = null;
|
|
469
421
|
}
|
|
422
|
+
markClosed();
|
|
470
423
|
const sessionId = liveSessionId;
|
|
471
424
|
liveSessionId = null;
|
|
472
425
|
if (sessionId !== null) {
|
|
@@ -476,22 +429,14 @@ function closePopover() {
|
|
|
476
429
|
}
|
|
477
430
|
}
|
|
478
431
|
}
|
|
479
|
-
function formatTarget(t, seq, time, preview) {
|
|
480
|
-
const d = new Date(time);
|
|
481
|
-
const hh = String(d.getHours()).padStart(2, "0");
|
|
482
|
-
const mm = String(d.getMinutes()).padStart(2, "0");
|
|
483
|
-
const previewText = preview.length > 0 ? preview : t("popover.noText");
|
|
484
|
-
return `seq ${seq} \xB7 ${hh}:${mm} \xB7 ${previewText}`;
|
|
485
|
-
}
|
|
486
432
|
function findCommand(chat, match) {
|
|
487
433
|
if (chat === void 0) return void 0;
|
|
488
434
|
let found;
|
|
489
|
-
for (const
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
}
|
|
435
|
+
for (const node of chatNodesOf(chat)) {
|
|
436
|
+
if (node.kind !== "command") continue;
|
|
437
|
+
const command = node.data;
|
|
438
|
+
if (!match(command)) continue;
|
|
439
|
+
if (found === void 0 || command.seq >= found.seq) found = command;
|
|
495
440
|
}
|
|
496
441
|
return found;
|
|
497
442
|
}
|
|
@@ -499,12 +444,10 @@ function knownCommandSeqs(session, chatOf, match) {
|
|
|
499
444
|
const known = /* @__PURE__ */ new Set();
|
|
500
445
|
const chat = chatOf(session);
|
|
501
446
|
if (chat === void 0) return known;
|
|
502
|
-
for (const
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
if (match(command)) known.add(command.seq);
|
|
507
|
-
}
|
|
447
|
+
for (const node of chatNodesOf(chat)) {
|
|
448
|
+
if (node.kind !== "command") continue;
|
|
449
|
+
const command = node.data;
|
|
450
|
+
if (match(command)) known.add(command.seq);
|
|
508
451
|
}
|
|
509
452
|
return known;
|
|
510
453
|
}
|
|
@@ -566,7 +509,7 @@ function moveFocus(root, dir) {
|
|
|
566
509
|
const next = index === -1 ? dir === 1 ? 0 : buttons.length - 1 : (index + dir + buttons.length) % buttons.length;
|
|
567
510
|
buttons[next]?.focus();
|
|
568
511
|
}
|
|
569
|
-
function renderImpactStep(root, opts, back, cached) {
|
|
512
|
+
function renderImpactStep(root, opts, back, reposition, cached) {
|
|
570
513
|
const { session, seq, t } = opts;
|
|
571
514
|
const impact = el("div", CLASS.popoverImpact, t("popover.impact.loading"));
|
|
572
515
|
const actions = el("div", CLASS.popoverActions);
|
|
@@ -584,6 +527,7 @@ function renderImpactStep(root, opts, back, cached) {
|
|
|
584
527
|
actions.append(confirm);
|
|
585
528
|
root.replaceChildren(impact, actions);
|
|
586
529
|
focusFirst(root);
|
|
530
|
+
reposition();
|
|
587
531
|
void (async () => {
|
|
588
532
|
const outcome = cached ?? await previewImpact(session.sessionId, seq);
|
|
589
533
|
if (outcome === null) {
|
|
@@ -619,16 +563,44 @@ function renderImpactStep(root, opts, back, cached) {
|
|
|
619
563
|
});
|
|
620
564
|
})().catch(() => {
|
|
621
565
|
impact.textContent = t("popover.impact.failed", { message: "unexpected error" });
|
|
566
|
+
}).finally(() => {
|
|
567
|
+
reposition();
|
|
622
568
|
});
|
|
623
569
|
}
|
|
624
570
|
function mountShell(root, anchor, onKeyDown) {
|
|
571
|
+
const margin = 12;
|
|
572
|
+
const gap = 4;
|
|
573
|
+
let flippedAbove = null;
|
|
625
574
|
const position = () => {
|
|
575
|
+
if (!root.isConnected) return;
|
|
576
|
+
if (!anchor.isConnected) {
|
|
577
|
+
if (popoverEl === root) closePopover();
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
626
580
|
const rect = anchor.getBoundingClientRect();
|
|
627
|
-
const gap = 4;
|
|
628
581
|
const height = root.offsetHeight;
|
|
629
|
-
|
|
582
|
+
if (flippedAbove === null) {
|
|
583
|
+
flippedAbove = rect.bottom + gap + height > window.innerHeight - margin;
|
|
584
|
+
}
|
|
585
|
+
const top = flippedAbove ? Math.max(margin, rect.top - gap - height) : Math.min(Math.max(margin, rect.bottom + gap), Math.max(margin, window.innerHeight - margin - height));
|
|
630
586
|
root.style.top = `${Math.round(top)}px`;
|
|
631
|
-
root.style.left = `${Math.round(Math.min(rect.right, window.innerWidth -
|
|
587
|
+
root.style.left = `${Math.round(Math.max(margin, Math.min(rect.right, window.innerWidth - margin - root.offsetWidth)))}px`;
|
|
588
|
+
};
|
|
589
|
+
let frame = 0;
|
|
590
|
+
const schedule = () => {
|
|
591
|
+
if (typeof requestAnimationFrame !== "function") {
|
|
592
|
+
position();
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (frame !== 0) return;
|
|
596
|
+
frame = requestAnimationFrame(() => {
|
|
597
|
+
frame = 0;
|
|
598
|
+
position();
|
|
599
|
+
});
|
|
600
|
+
};
|
|
601
|
+
const onScroll = (event) => {
|
|
602
|
+
if (event.target instanceof Node && root.contains(event.target)) return;
|
|
603
|
+
schedule();
|
|
632
604
|
};
|
|
633
605
|
const onPointerDown = (event) => {
|
|
634
606
|
const target = event.target;
|
|
@@ -639,19 +611,30 @@ function mountShell(root, anchor, onKeyDown) {
|
|
|
639
611
|
document.addEventListener("pointerdown", onPointerDown);
|
|
640
612
|
document.addEventListener("keydown", onKeyDown, true);
|
|
641
613
|
}, 0);
|
|
614
|
+
document.body.append(root);
|
|
615
|
+
position();
|
|
616
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => {
|
|
617
|
+
schedule();
|
|
618
|
+
});
|
|
619
|
+
observer?.observe(root);
|
|
620
|
+
window.addEventListener("scroll", onScroll, true);
|
|
621
|
+
window.addEventListener("resize", schedule);
|
|
642
622
|
const dispose = () => {
|
|
643
623
|
clearTimeout(deferred);
|
|
644
624
|
document.removeEventListener("pointerdown", onPointerDown);
|
|
645
625
|
document.removeEventListener("keydown", onKeyDown, true);
|
|
626
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
627
|
+
window.removeEventListener("resize", schedule);
|
|
628
|
+
observer?.disconnect();
|
|
629
|
+
if (frame !== 0) cancelAnimationFrame(frame);
|
|
646
630
|
};
|
|
647
|
-
document.body.append(root);
|
|
648
|
-
position();
|
|
649
631
|
return { position, dispose };
|
|
650
632
|
}
|
|
651
633
|
function openRetractPopover(opts) {
|
|
652
634
|
closePopover();
|
|
653
635
|
const { preview, anchor, t, retract, onRetract } = opts;
|
|
654
636
|
if (retract === void 0 || onRetract === void 0) return;
|
|
637
|
+
markOpen(anchor);
|
|
655
638
|
const root = el("div", CLASS.popover);
|
|
656
639
|
root.setAttribute("role", "dialog");
|
|
657
640
|
root.setAttribute("aria-label", t("popover.retract.title"));
|
|
@@ -711,6 +694,7 @@ function openPopover(opts) {
|
|
|
711
694
|
const { session, seq, time, preview, anchor, t } = opts;
|
|
712
695
|
const onRewind = opts.onRewind;
|
|
713
696
|
if (seq === void 0 || time === void 0 || onRewind === void 0) return;
|
|
697
|
+
markOpen(anchor);
|
|
714
698
|
const durableOpts = { session, seq, time, preview, anchor, t, onRewind };
|
|
715
699
|
const root = el("div", CLASS.popover);
|
|
716
700
|
root.setAttribute("role", "dialog");
|
|
@@ -718,11 +702,14 @@ function openPopover(opts) {
|
|
|
718
702
|
let bothState = { state: "loading" };
|
|
719
703
|
let impactOutcome = null;
|
|
720
704
|
let step = "modes";
|
|
705
|
+
let reposition = () => {
|
|
706
|
+
};
|
|
721
707
|
const renderModes = () => {
|
|
722
708
|
step = "modes";
|
|
709
|
+
const previewText = preview.length > 0 ? preview : t("popover.noText");
|
|
723
710
|
const children = [
|
|
724
711
|
el("div", CLASS.popoverTitle, t("popover.title")),
|
|
725
|
-
el("div", CLASS.popoverTarget,
|
|
712
|
+
el("div", CLASS.popoverTarget, previewText),
|
|
726
713
|
modeOption(t("popover.chat"), t("popover.chat.hint"), () => {
|
|
727
714
|
closePopover();
|
|
728
715
|
durableOpts.onRewind("chat");
|
|
@@ -741,20 +728,13 @@ function openPopover(opts) {
|
|
|
741
728
|
if (bothState.state === "loading") option.disabled = true;
|
|
742
729
|
children.push(option);
|
|
743
730
|
}
|
|
744
|
-
const actions = el("div", CLASS.popoverActions);
|
|
745
|
-
const cancel = document.createElement("button");
|
|
746
|
-
cancel.type = "button";
|
|
747
|
-
cancel.className = CLASS.popoverGhost;
|
|
748
|
-
cancel.textContent = t("popover.cancel");
|
|
749
|
-
cancel.addEventListener("click", closePopover);
|
|
750
|
-
actions.append(cancel);
|
|
751
|
-
children.push(actions);
|
|
752
731
|
root.replaceChildren(...children);
|
|
753
732
|
focusFirst(root);
|
|
733
|
+
reposition();
|
|
754
734
|
};
|
|
755
735
|
const renderImpact = () => {
|
|
756
736
|
step = "impact";
|
|
757
|
-
renderImpactStep(root, durableOpts, renderModes, impactOutcome);
|
|
737
|
+
renderImpactStep(root, durableOpts, renderModes, reposition, impactOutcome);
|
|
758
738
|
};
|
|
759
739
|
const onKeyDown = (event) => {
|
|
760
740
|
if (event.key === "ArrowDown") {
|
|
@@ -778,6 +758,7 @@ function openPopover(opts) {
|
|
|
778
758
|
};
|
|
779
759
|
renderModes();
|
|
780
760
|
const shell = mountShell(root, anchor, onKeyDown);
|
|
761
|
+
reposition = shell.position;
|
|
781
762
|
popoverEl = root;
|
|
782
763
|
disposeOutside = shell.dispose;
|
|
783
764
|
void (async () => {
|
|
@@ -789,17 +770,303 @@ function openPopover(opts) {
|
|
|
789
770
|
bothState = { state: "error", message: outcome?.kind === "error" ? outcome.text : "preview request timed out" };
|
|
790
771
|
}
|
|
791
772
|
renderModes();
|
|
792
|
-
shell.position();
|
|
793
773
|
})().catch(() => {
|
|
794
774
|
bothState = { state: "error", message: "unexpected error" };
|
|
795
775
|
renderModes();
|
|
796
|
-
shell.position();
|
|
797
776
|
});
|
|
798
777
|
}
|
|
799
778
|
|
|
779
|
+
// src/client/log.ts
|
|
780
|
+
var NS = "dsh-rewind";
|
|
781
|
+
var DEBUG_KEY = "dsh-rewind.debug";
|
|
782
|
+
var ALWAYS_ON = /* @__PURE__ */ new Set(["error", "warn"]);
|
|
783
|
+
function switchValue() {
|
|
784
|
+
try {
|
|
785
|
+
return window.localStorage.getItem(DEBUG_KEY) ?? "";
|
|
786
|
+
} catch {
|
|
787
|
+
return "";
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
function matches(value, ns) {
|
|
791
|
+
for (const entry of value.split(",")) {
|
|
792
|
+
const part = entry.trim();
|
|
793
|
+
if (part === "") continue;
|
|
794
|
+
if (part === "*" || part === `${NS}*`) return true;
|
|
795
|
+
if (part.endsWith("*")) {
|
|
796
|
+
if (ns.startsWith(part.slice(0, -1))) return true;
|
|
797
|
+
} else if (ns === part) {
|
|
798
|
+
return true;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
function tag(scope) {
|
|
804
|
+
return `[${NS}:${scope}]`;
|
|
805
|
+
}
|
|
806
|
+
function log(level, scope, message, data) {
|
|
807
|
+
if (ALWAYS_ON.has(level)) {
|
|
808
|
+
console[level](tag(scope), message, data);
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
if (!matches(switchValue(), `${NS}:${scope}`)) return;
|
|
812
|
+
console.info(tag(scope), message, data);
|
|
813
|
+
}
|
|
814
|
+
var rewindLog = {
|
|
815
|
+
error: (scope, message, data) => log("error", scope, message, data),
|
|
816
|
+
warn: (scope, message, data) => log("warn", scope, message, data),
|
|
817
|
+
info: (scope, message, data) => log("info", scope, message, data),
|
|
818
|
+
debug: (scope, message, data) => log("debug", scope, message, data)
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
// src/client/visibility.ts
|
|
822
|
+
var patches = /* @__PURE__ */ new Map();
|
|
823
|
+
var currentCleanup;
|
|
824
|
+
function installChatViewVisibility(ctx) {
|
|
825
|
+
let stopped = false;
|
|
826
|
+
const start = () => {
|
|
827
|
+
const scope = ctx.inject?.(["uiConversation"], (child) => {
|
|
828
|
+
if (!stopped) installOn(child.get("uiConversation"), ctx.sessions);
|
|
829
|
+
});
|
|
830
|
+
if (ctx.inject === void 0) {
|
|
831
|
+
installOn(ctx.get("uiConversation"), ctx.sessions);
|
|
832
|
+
}
|
|
833
|
+
return () => {
|
|
834
|
+
stopped = true;
|
|
835
|
+
currentCleanup?.();
|
|
836
|
+
currentCleanup = void 0;
|
|
837
|
+
if (typeof scope === "function") scope();
|
|
838
|
+
};
|
|
839
|
+
};
|
|
840
|
+
if (ctx.effect === void 0) {
|
|
841
|
+
start();
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
ctx.effect(start, "dsh-rewind chat visibility");
|
|
845
|
+
}
|
|
846
|
+
function installOn(ui, sessions) {
|
|
847
|
+
currentCleanup?.();
|
|
848
|
+
currentCleanup = void 0;
|
|
849
|
+
if (ui?.views === void 0) return;
|
|
850
|
+
const views = ui.views;
|
|
851
|
+
const ensure = () => {
|
|
852
|
+
try {
|
|
853
|
+
const definition = views.entries().find((candidate) => candidate.target === "chat");
|
|
854
|
+
if (definition === void 0 || typeof definition.create !== "function") return;
|
|
855
|
+
const current = patches.get(definition);
|
|
856
|
+
const create = definition.create;
|
|
857
|
+
if (current !== void 0 && create === current.wrapper) return;
|
|
858
|
+
const wrapper = function wrappedChatBuilder() {
|
|
859
|
+
return new RewindVisibilityBuilder(create.call(definition));
|
|
860
|
+
};
|
|
861
|
+
const mutable = definition;
|
|
862
|
+
mutable.create = wrapper;
|
|
863
|
+
patches.set(definition, { original: create, wrapper });
|
|
864
|
+
rewindLog.info("visibility", "installed Chat snapshot visibility wrapper");
|
|
865
|
+
rebuildOpenSessions(ui, sessions);
|
|
866
|
+
} catch (error) {
|
|
867
|
+
rewindLog.error("visibility", "Chat visibility install probe failed", error);
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
let unsubscribe;
|
|
871
|
+
try {
|
|
872
|
+
unsubscribe = views.subscribe?.(ensure);
|
|
873
|
+
} catch (error) {
|
|
874
|
+
rewindLog.warn("visibility", "Chat view subscription failed", error);
|
|
875
|
+
}
|
|
876
|
+
ensure();
|
|
877
|
+
currentCleanup = () => {
|
|
878
|
+
unsubscribe?.();
|
|
879
|
+
restorePatches();
|
|
880
|
+
rebuildOpenSessions(ui, sessions);
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
function restorePatches() {
|
|
884
|
+
for (const [definition, record] of patches) {
|
|
885
|
+
const mutable = definition;
|
|
886
|
+
if (mutable.create === record.wrapper) mutable.create = record.original;
|
|
887
|
+
}
|
|
888
|
+
patches = /* @__PURE__ */ new Map();
|
|
889
|
+
}
|
|
890
|
+
function rebuildOpenSessions(ui, sessions) {
|
|
891
|
+
const state = sessions?.list?.getSnapshot();
|
|
892
|
+
if (state === void 0) return;
|
|
893
|
+
const ids = /* @__PURE__ */ new Set([...state.ids ?? [], ...Object.keys(state.byId ?? {})]);
|
|
894
|
+
for (const id of ids) {
|
|
895
|
+
const row = state.byId?.[id];
|
|
896
|
+
const retained = row?.retainedBy;
|
|
897
|
+
if (retained === void 0 || !Object.values(retained).some((count) => (count ?? 0) > 0)) continue;
|
|
898
|
+
try {
|
|
899
|
+
ui.binding?.(id)?.rebuild?.();
|
|
900
|
+
} catch (error) {
|
|
901
|
+
rewindLog.warn("visibility", `chat rebuild failed for ${id}`, error);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
var RewindVisibilityBuilder = class {
|
|
906
|
+
/** @param inner - the real Chat builder. */
|
|
907
|
+
constructor(inner) {
|
|
908
|
+
__publicField(this, "inner", inner);
|
|
909
|
+
__publicField(this, "originals", /* @__PURE__ */ new Map());
|
|
910
|
+
__publicField(this, "commands", /* @__PURE__ */ new Map());
|
|
911
|
+
__publicField(this, "byTurn", /* @__PURE__ */ new Map());
|
|
912
|
+
__publicField(this, "turnProcess", /* @__PURE__ */ new Map());
|
|
913
|
+
__publicField(this, "derived", /* @__PURE__ */ new Map());
|
|
914
|
+
__publicField(this, "cuts", []);
|
|
915
|
+
__publicField(this, "cutSignature", "[]");
|
|
916
|
+
__publicField(this, "lastSignature", "[]");
|
|
917
|
+
}
|
|
918
|
+
get empty() {
|
|
919
|
+
return this.inner.empty;
|
|
920
|
+
}
|
|
921
|
+
replace(input) {
|
|
922
|
+
this.setAll(input.nodes);
|
|
923
|
+
this.lastSignature = this.cutSignature;
|
|
924
|
+
return this.inner.replace({ nodes: this.deriveAll(), timeline: input.timeline, ...changed(input) });
|
|
925
|
+
}
|
|
926
|
+
apply(input) {
|
|
927
|
+
const affected = /* @__PURE__ */ new Set();
|
|
928
|
+
let commandsChanged = false;
|
|
929
|
+
for (const node of input.upserts) {
|
|
930
|
+
const previous = this.originals.get(node.key);
|
|
931
|
+
const previousTurn = previous === void 0 ? void 0 : turnOf(previous);
|
|
932
|
+
const nextTurn = turnOf(node);
|
|
933
|
+
if (previousTurn !== void 0) affected.add(previousTurn);
|
|
934
|
+
if (nextTurn !== void 0) affected.add(nextTurn);
|
|
935
|
+
if (previous?.kind === "command" || node.kind === "command") commandsChanged = true;
|
|
936
|
+
this.setOriginal(node);
|
|
937
|
+
}
|
|
938
|
+
if (commandsChanged) this.refreshCuts();
|
|
939
|
+
if (this.cutSignature !== this.lastSignature) {
|
|
940
|
+
this.lastSignature = this.cutSignature;
|
|
941
|
+
return this.inner.replace({ nodes: this.deriveAll(), timeline: input.timeline, ...changed(input) });
|
|
942
|
+
}
|
|
943
|
+
const cuts = this.cuts;
|
|
944
|
+
const upserts = /* @__PURE__ */ new Map();
|
|
945
|
+
for (const node of input.upserts) upserts.set(node.key, this.deriveOne(node, cuts));
|
|
946
|
+
for (const turn of affected) {
|
|
947
|
+
const processKey = this.turnProcess.get(turn);
|
|
948
|
+
const base = processKey === void 0 ? void 0 : this.originals.get(processKey);
|
|
949
|
+
if (base === void 0) continue;
|
|
950
|
+
const next = this.deriveTurnProcess(base, cuts, turn, this.deriveOne(base, cuts));
|
|
951
|
+
if (this.derived.get(processKey) !== next) upserts.set(processKey, next);
|
|
952
|
+
}
|
|
953
|
+
const list = [...upserts.values()];
|
|
954
|
+
for (const node of list) this.derived.set(node.key, node);
|
|
955
|
+
return this.inner.apply({ upserts: list, timeline: input.timeline, ...changed(input) });
|
|
956
|
+
}
|
|
957
|
+
groupInput() {
|
|
958
|
+
return this.inner.groupInput?.();
|
|
959
|
+
}
|
|
960
|
+
publish() {
|
|
961
|
+
this.inner.publish?.();
|
|
962
|
+
}
|
|
963
|
+
setAll(nodes) {
|
|
964
|
+
this.originals.clear();
|
|
965
|
+
this.commands.clear();
|
|
966
|
+
this.byTurn.clear();
|
|
967
|
+
this.turnProcess.clear();
|
|
968
|
+
this.derived.clear();
|
|
969
|
+
for (const node of nodes) this.setOriginal(node);
|
|
970
|
+
this.refreshCuts();
|
|
971
|
+
}
|
|
972
|
+
setOriginal(node) {
|
|
973
|
+
const previous = this.originals.get(node.key);
|
|
974
|
+
if (previous !== void 0) this.unindex(previous);
|
|
975
|
+
this.originals.set(node.key, node);
|
|
976
|
+
if (node.kind === "command") this.commands.set(node.key, node);
|
|
977
|
+
const turn = turnOf(node);
|
|
978
|
+
if (turn === void 0) return;
|
|
979
|
+
const members = this.byTurn.get(turn) ?? /* @__PURE__ */ new Map();
|
|
980
|
+
members.set(node.key, node);
|
|
981
|
+
this.byTurn.set(turn, members);
|
|
982
|
+
if (node.kind === "turn-process") this.turnProcess.set(turn, node.key);
|
|
983
|
+
}
|
|
984
|
+
unindex(node) {
|
|
985
|
+
if (node.kind === "command") this.commands.delete(node.key);
|
|
986
|
+
const turn = turnOf(node);
|
|
987
|
+
if (turn === void 0) return;
|
|
988
|
+
const members = this.byTurn.get(turn);
|
|
989
|
+
if (members === void 0) return;
|
|
990
|
+
members.delete(node.key);
|
|
991
|
+
if (members.size === 0) this.byTurn.delete(turn);
|
|
992
|
+
if (node.kind === "turn-process" && this.turnProcess.get(turn) === node.key) {
|
|
993
|
+
this.turnProcess.delete(turn);
|
|
994
|
+
for (const member of members.values()) {
|
|
995
|
+
if (member.kind === "turn-process") {
|
|
996
|
+
this.turnProcess.set(turn, member.key);
|
|
997
|
+
break;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
refreshCuts() {
|
|
1003
|
+
this.cuts = rewindCutsOf(this.commands.values());
|
|
1004
|
+
this.cutSignature = JSON.stringify(
|
|
1005
|
+
this.cuts.map((cut) => `${cut.target}:${cut.marker}`).sort()
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
deriveAll() {
|
|
1009
|
+
const cuts = this.cuts;
|
|
1010
|
+
const derived = /* @__PURE__ */ new Map();
|
|
1011
|
+
for (const node of this.originals.values()) derived.set(node.key, this.deriveOne(node, cuts));
|
|
1012
|
+
for (const [turn, key] of this.turnProcess) {
|
|
1013
|
+
const base = this.originals.get(key);
|
|
1014
|
+
if (base === void 0) continue;
|
|
1015
|
+
const current = derived.get(key) ?? this.deriveOne(base, cuts);
|
|
1016
|
+
derived.set(key, this.deriveTurnProcess(base, cuts, turn, current));
|
|
1017
|
+
}
|
|
1018
|
+
const result = [...derived.values()];
|
|
1019
|
+
this.derived = derived;
|
|
1020
|
+
return result;
|
|
1021
|
+
}
|
|
1022
|
+
deriveOne(node, cuts) {
|
|
1023
|
+
const base = this.originals.get(node.key) ?? node;
|
|
1024
|
+
if (base.kind === "command") {
|
|
1025
|
+
const command = base.data;
|
|
1026
|
+
if (command.name !== void 0 && command.name !== null && ENGINE_COMMANDS.has(command.name)) {
|
|
1027
|
+
const args = command.args ?? "";
|
|
1028
|
+
const probe = args.includes("preview") || args.includes("__candidates");
|
|
1029
|
+
const executed = command.outcome?.kind === "success" && command.outcome.sourceEventSeq !== void 0;
|
|
1030
|
+
if (probe || executed) return hidden(base);
|
|
1031
|
+
}
|
|
1032
|
+
return base;
|
|
1033
|
+
}
|
|
1034
|
+
const contained = cuts.some((cut) => cut.target <= base.anchorSeq && base.anchorSeq <= cut.marker);
|
|
1035
|
+
return contained ? hidden(base) : base;
|
|
1036
|
+
}
|
|
1037
|
+
deriveTurnProcess(base, cuts, turn = turnOf(base), current = this.deriveOne(base, cuts)) {
|
|
1038
|
+
if (turn === void 0 || current.visibility === "hidden") return current;
|
|
1039
|
+
const members = this.byTurn.get(turn);
|
|
1040
|
+
if (members === void 0) return current;
|
|
1041
|
+
let count = 0;
|
|
1042
|
+
let allHidden = true;
|
|
1043
|
+
for (const member of members.values()) {
|
|
1044
|
+
if (member.key === base.key) continue;
|
|
1045
|
+
count += 1;
|
|
1046
|
+
if (this.deriveOne(member, cuts).visibility !== "hidden") {
|
|
1047
|
+
allHidden = false;
|
|
1048
|
+
break;
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
if (count === 0) return current;
|
|
1052
|
+
return allHidden ? hidden(base) : current;
|
|
1053
|
+
}
|
|
1054
|
+
};
|
|
1055
|
+
function hidden(node) {
|
|
1056
|
+
return node.visibility === "hidden" ? node : { ...node, visibility: "hidden" };
|
|
1057
|
+
}
|
|
1058
|
+
function turnOf(node) {
|
|
1059
|
+
const turn = node.location?.turn?.turn;
|
|
1060
|
+
return typeof turn === "number" ? turn : void 0;
|
|
1061
|
+
}
|
|
1062
|
+
function changed(input) {
|
|
1063
|
+
return input.changedTurns === void 0 ? {} : { changedTurns: input.changedTurns };
|
|
1064
|
+
}
|
|
1065
|
+
|
|
800
1066
|
// src/client/portals.tsx
|
|
801
1067
|
var import_react = require("react");
|
|
802
1068
|
var import_react_dom = require("react-dom");
|
|
1069
|
+
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
803
1070
|
|
|
804
1071
|
// src/client/pending.ts
|
|
805
1072
|
var QUEUE_PREVIEW_CHARS = 200;
|
|
@@ -831,11 +1098,11 @@ function matchPendingRows(rows, steering) {
|
|
|
831
1098
|
for (let i = 0; i < rows.length; i++) {
|
|
832
1099
|
const row = rows[i];
|
|
833
1100
|
const item = steering[i];
|
|
834
|
-
matched.push(item !== void 0 &&
|
|
1101
|
+
matched.push(item !== void 0 && matches2(item, row) ? item.id : null);
|
|
835
1102
|
}
|
|
836
1103
|
return matched;
|
|
837
1104
|
}
|
|
838
|
-
function
|
|
1105
|
+
function matches2(item, row) {
|
|
839
1106
|
if (item.attachments > 0) return row.attachments === item.attachments;
|
|
840
1107
|
return row.text === (item.text ?? "");
|
|
841
1108
|
}
|
|
@@ -845,48 +1112,6 @@ function retractSpan(steering, targetId) {
|
|
|
845
1112
|
return steering.slice(index).map((item) => item.id);
|
|
846
1113
|
}
|
|
847
1114
|
|
|
848
|
-
// src/client/log.ts
|
|
849
|
-
var NS = "dsh-rewind";
|
|
850
|
-
var DEBUG_KEY = "dsh-rewind.debug";
|
|
851
|
-
var ALWAYS_ON = /* @__PURE__ */ new Set(["error", "warn"]);
|
|
852
|
-
function switchValue() {
|
|
853
|
-
try {
|
|
854
|
-
return window.localStorage.getItem(DEBUG_KEY) ?? "";
|
|
855
|
-
} catch {
|
|
856
|
-
return "";
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
function matches2(value, ns) {
|
|
860
|
-
for (const entry of value.split(",")) {
|
|
861
|
-
const part = entry.trim();
|
|
862
|
-
if (part === "") continue;
|
|
863
|
-
if (part === "*" || part === `${NS}*`) return true;
|
|
864
|
-
if (part.endsWith("*")) {
|
|
865
|
-
if (ns.startsWith(part.slice(0, -1))) return true;
|
|
866
|
-
} else if (ns === part) {
|
|
867
|
-
return true;
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
return false;
|
|
871
|
-
}
|
|
872
|
-
function tag(scope) {
|
|
873
|
-
return `[${NS}:${scope}]`;
|
|
874
|
-
}
|
|
875
|
-
function log(level, scope, message, data) {
|
|
876
|
-
if (ALWAYS_ON.has(level)) {
|
|
877
|
-
console[level](tag(scope), message, data);
|
|
878
|
-
return;
|
|
879
|
-
}
|
|
880
|
-
if (!matches2(switchValue(), `${NS}:${scope}`)) return;
|
|
881
|
-
console.info(tag(scope), message, data);
|
|
882
|
-
}
|
|
883
|
-
var rewindLog = {
|
|
884
|
-
error: (scope, message, data) => log("error", scope, message, data),
|
|
885
|
-
warn: (scope, message, data) => log("warn", scope, message, data),
|
|
886
|
-
info: (scope, message, data) => log("info", scope, message, data),
|
|
887
|
-
debug: (scope, message, data) => log("debug", scope, message, data)
|
|
888
|
-
};
|
|
889
|
-
|
|
890
1115
|
// src/client/portals.tsx
|
|
891
1116
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
892
1117
|
function fillComposerEditable(text) {
|
|
@@ -1018,7 +1243,6 @@ function showHint(text) {
|
|
|
1018
1243
|
}
|
|
1019
1244
|
var COMPOSER_EDITABLE_SELECTOR = "[data-composer-input]";
|
|
1020
1245
|
var USER_SEAT_SELECTOR = '[data-chat-flow-kind="user"][data-chat-anchor-key], [data-chat-flow-kind="steering"][data-chat-anchor-key]';
|
|
1021
|
-
var CHAT_SEAT_SELECTOR = "[data-chat-anchor-key]";
|
|
1022
1246
|
var IGNORED_PORTAL_SCOPE = [
|
|
1023
1247
|
"[data-composer-seat]",
|
|
1024
1248
|
"[data-composer-input]",
|
|
@@ -1026,14 +1250,6 @@ var IGNORED_PORTAL_SCOPE = [
|
|
|
1026
1250
|
"[data-sidebar-chat]",
|
|
1027
1251
|
"[data-plugin-panel]"
|
|
1028
1252
|
].join(", ");
|
|
1029
|
-
var GROUP_SHELL_SELECTOR = '[data-chat-anchor-key^="group:"]';
|
|
1030
|
-
function resolveSeatAnchorSeq(element, chat) {
|
|
1031
|
-
if (chat === void 0) return void 0;
|
|
1032
|
-
const flowKey = element.dataset.chatAnchorKey;
|
|
1033
|
-
const nodeKey = element.dataset.chatNodeKey;
|
|
1034
|
-
const node = (flowKey !== void 0 ? chat.nodes.get(flowKey) : void 0) ?? (nodeKey !== void 0 ? chat.nodes.get(nodeKey) : void 0);
|
|
1035
|
-
return node?.anchorSeq;
|
|
1036
|
-
}
|
|
1037
1253
|
var PENDING_SEAT_SELECTOR = "[data-pending-steering]";
|
|
1038
1254
|
var MESSAGE_ATTACHMENT_SELECTOR = "[data-message-attachments]";
|
|
1039
1255
|
function actionsContainerOf(row) {
|
|
@@ -1043,47 +1259,7 @@ function actionsContainerOf(row) {
|
|
|
1043
1259
|
if (structural instanceof HTMLElement && structural.querySelector("button") !== null) return structural;
|
|
1044
1260
|
return void 0;
|
|
1045
1261
|
}
|
|
1046
|
-
function
|
|
1047
|
-
if (chat === void 0) return;
|
|
1048
|
-
const shells = /* @__PURE__ */ new Map();
|
|
1049
|
-
for (const seat of seats) {
|
|
1050
|
-
if (seat.matches(GROUP_SHELL_SELECTOR)) continue;
|
|
1051
|
-
const anchor = resolveSeatAnchorSeq(seat, chat);
|
|
1052
|
-
const withdrawn = anchor !== void 0 && hiddenSeqs.has(anchor);
|
|
1053
|
-
if (withdrawn) {
|
|
1054
|
-
seat.style.display = "none";
|
|
1055
|
-
seat.dataset.dshRewindHidden = "true";
|
|
1056
|
-
hidden.add(seat);
|
|
1057
|
-
} else if (hidden.has(seat)) {
|
|
1058
|
-
seat.style.display = "";
|
|
1059
|
-
delete seat.dataset.dshRewindHidden;
|
|
1060
|
-
hidden.delete(seat);
|
|
1061
|
-
}
|
|
1062
|
-
if (seat.dataset.chatNodeKey === void 0) continue;
|
|
1063
|
-
const shell = seat.parentElement?.closest(GROUP_SHELL_SELECTOR);
|
|
1064
|
-
if (shell === null || shell === void 0) continue;
|
|
1065
|
-
shells.set(shell, (shells.get(shell) ?? true) && withdrawn);
|
|
1066
|
-
}
|
|
1067
|
-
for (const [shell, allWithdrawn] of shells) {
|
|
1068
|
-
if (allWithdrawn) {
|
|
1069
|
-
shell.style.display = "none";
|
|
1070
|
-
shell.dataset.dshRewindHidden = "true";
|
|
1071
|
-
hidden.add(shell);
|
|
1072
|
-
} else if (hidden.has(shell)) {
|
|
1073
|
-
shell.style.display = "";
|
|
1074
|
-
delete shell.dataset.dshRewindHidden;
|
|
1075
|
-
hidden.delete(shell);
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
function showHiddenSeats(hidden) {
|
|
1080
|
-
for (const element of hidden) {
|
|
1081
|
-
element.style.display = "";
|
|
1082
|
-
delete element.dataset.dshRewindHidden;
|
|
1083
|
-
}
|
|
1084
|
-
hidden.clear();
|
|
1085
|
-
}
|
|
1086
|
-
function collectTargets(chat, hiddenSeqs) {
|
|
1262
|
+
function collectTargets(chat) {
|
|
1087
1263
|
const rows = /* @__PURE__ */ new Map();
|
|
1088
1264
|
for (const element of document.querySelectorAll(USER_SEAT_SELECTOR)) {
|
|
1089
1265
|
const key = element.dataset.chatAnchorKey;
|
|
@@ -1094,7 +1270,6 @@ function collectTargets(chat, hiddenSeqs) {
|
|
|
1094
1270
|
const node = chat.nodes.get(key);
|
|
1095
1271
|
if (node === void 0 || node.kind !== "user" && node.kind !== "steering") continue;
|
|
1096
1272
|
const user = node.data;
|
|
1097
|
-
if (hiddenSeqs.has(node.anchorSeq ?? user.seq)) continue;
|
|
1098
1273
|
const row = rows.get(key);
|
|
1099
1274
|
const actions = actionsContainerOf(row);
|
|
1100
1275
|
if (actions === void 0) continue;
|
|
@@ -1105,9 +1280,9 @@ function collectTargets(chat, hiddenSeqs) {
|
|
|
1105
1280
|
function isRewindInertSession(snapshot) {
|
|
1106
1281
|
return snapshot.subagent !== null && snapshot.subagent !== void 0;
|
|
1107
1282
|
}
|
|
1108
|
-
function collectDurableTargets(snapshot, chat
|
|
1283
|
+
function collectDurableTargets(snapshot, chat) {
|
|
1109
1284
|
if (chat === void 0 || isRewindInertSession(snapshot)) return [];
|
|
1110
|
-
return collectTargets(chat
|
|
1285
|
+
return collectTargets(chat);
|
|
1111
1286
|
}
|
|
1112
1287
|
function inboxOf(session) {
|
|
1113
1288
|
return session.projections.faceOf(INBOX_PROJECTION).getSnapshot();
|
|
@@ -1156,7 +1331,6 @@ function sameTargets(left, right) {
|
|
|
1156
1331
|
}
|
|
1157
1332
|
function RewindPortals({ sessionId, sessionOf, chatOf, isMainViewSession, watchChat, t, subscribeLocale, setComposerText, restoreImages }) {
|
|
1158
1333
|
const [targets, setTargets] = (0, import_react.useState)([]);
|
|
1159
|
-
const hidden = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
1160
1334
|
const [, forceRender] = (0, import_react.useReducer)((count) => count + 1, 0);
|
|
1161
1335
|
(0, import_react.useEffect)(() => subscribeLocale(() => {
|
|
1162
1336
|
forceRender();
|
|
@@ -1176,17 +1350,7 @@ function RewindPortals({ sessionId, sessionOf, chatOf, isMainViewSession, watchC
|
|
|
1176
1350
|
}
|
|
1177
1351
|
const snapshot = session.getSnapshot();
|
|
1178
1352
|
const chat = chatOf(session);
|
|
1179
|
-
const
|
|
1180
|
-
for (const element of hidden.current) if (!element.isConnected) hidden.current.delete(element);
|
|
1181
|
-
if (hiddenSeqs.size > 0 || hidden.current.size > 0) {
|
|
1182
|
-
hideWithdrawnSeats(
|
|
1183
|
-
chat,
|
|
1184
|
-
chat === void 0 ? [] : document.querySelectorAll(CHAT_SEAT_SELECTOR),
|
|
1185
|
-
hiddenSeqs,
|
|
1186
|
-
hidden.current
|
|
1187
|
-
);
|
|
1188
|
-
}
|
|
1189
|
-
const durable = collectDurableTargets(snapshot, chat, hiddenSeqs);
|
|
1353
|
+
const durable = collectDurableTargets(snapshot, chat);
|
|
1190
1354
|
const next = [...durable, ...collectPendingTargets(snapshot, steeringItemsOf(inboxOf(session)?.["next-step"]))];
|
|
1191
1355
|
setTargets((current) => sameTargets(current, next) ? current : next);
|
|
1192
1356
|
};
|
|
@@ -1214,26 +1378,17 @@ function RewindPortals({ sessionId, sessionOf, chatOf, isMainViewSession, watchC
|
|
|
1214
1378
|
const unsubscribeChat = watchChat(sessionId, queueRefresh);
|
|
1215
1379
|
const observer = new MutationObserver((records) => {
|
|
1216
1380
|
for (const record of records) {
|
|
1217
|
-
if (record.type === "attributes") {
|
|
1218
|
-
const target = record.target;
|
|
1219
|
-
if (target instanceof HTMLElement && hidden.current.has(target) && target.style.display !== "none") {
|
|
1220
|
-
queueRefresh();
|
|
1221
|
-
return;
|
|
1222
|
-
}
|
|
1223
|
-
continue;
|
|
1224
|
-
}
|
|
1225
1381
|
const node = record.target instanceof Element ? record.target : record.target.parentElement;
|
|
1226
1382
|
if (node !== null && node.closest(IGNORED_PORTAL_SCOPE) !== null) continue;
|
|
1227
1383
|
queueRefresh();
|
|
1228
1384
|
return;
|
|
1229
1385
|
}
|
|
1230
1386
|
});
|
|
1231
|
-
observer.observe(document.body, { childList: true, subtree: true
|
|
1387
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
1232
1388
|
return () => {
|
|
1233
1389
|
active = false;
|
|
1234
1390
|
observer.disconnect();
|
|
1235
1391
|
unsubscribeChat();
|
|
1236
|
-
showHiddenSeats(hidden.current);
|
|
1237
1392
|
unsubscribeInbox?.();
|
|
1238
1393
|
unsubscribeInbox = void 0;
|
|
1239
1394
|
inboxOwner = void 0;
|
|
@@ -1291,17 +1446,17 @@ function RewindButton({ target, sessionId, sessionOf, chatOf, watchChat, isMainV
|
|
|
1291
1446
|
}
|
|
1292
1447
|
});
|
|
1293
1448
|
};
|
|
1294
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1449
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Tooltip, { label: t("button.title"), side: "bottom", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1295
1450
|
"button",
|
|
1296
1451
|
{
|
|
1297
1452
|
type: "button",
|
|
1298
1453
|
className: CLASS.button,
|
|
1299
1454
|
"aria-label": t("button.aria"),
|
|
1300
|
-
|
|
1455
|
+
"aria-haspopup": "dialog",
|
|
1301
1456
|
onClick,
|
|
1302
1457
|
dangerouslySetInnerHTML: { __html: REWIND_ICON_SVG }
|
|
1303
1458
|
}
|
|
1304
|
-
);
|
|
1459
|
+
) });
|
|
1305
1460
|
}
|
|
1306
1461
|
function composerText() {
|
|
1307
1462
|
const surface = composerSurface();
|
|
@@ -1343,17 +1498,17 @@ function RetractButton({ target, sessionId, sessionOf, setComposerText, t }) {
|
|
|
1343
1498
|
}
|
|
1344
1499
|
});
|
|
1345
1500
|
};
|
|
1346
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1501
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Tooltip, { label: t("button.retract.title"), side: "bottom", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1347
1502
|
"button",
|
|
1348
1503
|
{
|
|
1349
1504
|
type: "button",
|
|
1350
1505
|
className: CLASS.button,
|
|
1351
1506
|
"aria-label": t("button.retract.aria"),
|
|
1352
|
-
|
|
1507
|
+
"aria-haspopup": "dialog",
|
|
1353
1508
|
onClick,
|
|
1354
1509
|
dangerouslySetInnerHTML: { __html: REWIND_ICON_SVG }
|
|
1355
1510
|
}
|
|
1356
|
-
);
|
|
1511
|
+
) });
|
|
1357
1512
|
}
|
|
1358
1513
|
function createRewindBridge(deps) {
|
|
1359
1514
|
return function RewindBridge({ sessionId }) {
|
|
@@ -1421,9 +1576,9 @@ async function candidatesOverRpc(connection, sessionId) {
|
|
|
1421
1576
|
}
|
|
1422
1577
|
|
|
1423
1578
|
// src/client/build-info.ts
|
|
1424
|
-
var PLUGIN_VERSION = true ? "0.
|
|
1579
|
+
var PLUGIN_VERSION = true ? "0.19.0" : "dev";
|
|
1425
1580
|
var PLUGIN_PACKAGE = "dsh-rewind-plugin";
|
|
1426
|
-
var BUILD_HASH = true ? "
|
|
1581
|
+
var BUILD_HASH = true ? "bccc8c9b" : "dev";
|
|
1427
1582
|
|
|
1428
1583
|
// src/client/locales.ts
|
|
1429
1584
|
var zh = {
|
|
@@ -1438,11 +1593,11 @@ var zh = {
|
|
|
1438
1593
|
"popover.retract.hint": "\u64A4\u56DE\u8FD9\u6761\u53CA\u4E4B\u540E\u7684\u63D2\u8BDD\u6D88\u606F\uFF0C\u4E0D\u6253\u65AD\u5F53\u524D\u751F\u6210",
|
|
1439
1594
|
"popover.retract.confirm": "\u786E\u8BA4\u56DE\u9000",
|
|
1440
1595
|
"popover.chat": "\u4EC5\u56DE\u9000\u5BF9\u8BDD",
|
|
1441
|
-
"popover.chat.hint": "\
|
|
1442
|
-
"popover.both": "\u56DE\u9000\u5BF9\u8BDD\u548C\
|
|
1443
|
-
"popover.both.hint": "\
|
|
1596
|
+
"popover.chat.hint": "\u4EC5\u56DE\u9000\u4E0A\u4E0B\u6587\uFF0C\u4E0D\u52A8\u5DE5\u4F5C\u533A\u6587\u4EF6",
|
|
1597
|
+
"popover.both": "\u56DE\u9000\u5BF9\u8BDD\u548C\u6587\u4EF6",
|
|
1598
|
+
"popover.both.hint": "\u56DE\u9000\u4E0A\u4E0B\u6587\u5E76\u8FD8\u539F\u5DE5\u4F5C\u533A\u6587\u4EF6",
|
|
1444
1599
|
"popover.checking": "\u6B63\u5728\u68C0\u67E5\u6587\u4EF6\u53D8\u66F4\u2026",
|
|
1445
|
-
"popover.noChanges": "\
|
|
1600
|
+
"popover.noChanges": "\u65E0\u53EF\u8FD8\u539F\u7684\u6587\u4EF6\u53D8\u66F4",
|
|
1446
1601
|
"popover.backupDisabled": "\u5FEB\u7167\u5907\u4EFD\u5DF2\u5173\u95ED\uFF0C\u8FD8\u539F\u53EF\u80FD\u4E0D\u5145\u5206",
|
|
1447
1602
|
"popover.cancel": "\u53D6\u6D88",
|
|
1448
1603
|
"popover.impact.loading": "\u6B63\u5728\u83B7\u53D6\u5F71\u54CD\u6E05\u5355\u2026",
|
|
@@ -1481,11 +1636,11 @@ var en = {
|
|
|
1481
1636
|
"popover.retract.hint": "Retracts this pending message and the ones after it, without interrupting the run",
|
|
1482
1637
|
"popover.retract.confirm": "Confirm rewind",
|
|
1483
1638
|
"popover.chat": "Rewind conversation only",
|
|
1484
|
-
"popover.chat.hint": "
|
|
1485
|
-
"popover.both": "Rewind conversation and
|
|
1486
|
-
"popover.both.hint": "
|
|
1639
|
+
"popover.chat.hint": "Context only; workspace untouched",
|
|
1640
|
+
"popover.both": "Rewind conversation and files",
|
|
1641
|
+
"popover.both.hint": "Context and restore workspace files",
|
|
1487
1642
|
"popover.checking": "Checking for file changes\u2026",
|
|
1488
|
-
"popover.noChanges": "No
|
|
1643
|
+
"popover.noChanges": "No restorable file changes",
|
|
1489
1644
|
"popover.backupDisabled": "Snapshots off; the restore may be incomplete",
|
|
1490
1645
|
"popover.cancel": "Cancel",
|
|
1491
1646
|
"popover.impact.loading": "Fetching impact list\u2026",
|
|
@@ -1514,7 +1669,7 @@ var en = {
|
|
|
1514
1669
|
};
|
|
1515
1670
|
|
|
1516
1671
|
// src/client/settings-card.tsx
|
|
1517
|
-
var
|
|
1672
|
+
var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
1518
1673
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1519
1674
|
var SETTINGS_ENTRY_ID = "dsh-rewind-plugin";
|
|
1520
1675
|
var DEFAULT_MAX_AGE_DAYS = 30;
|
|
@@ -1542,10 +1697,10 @@ function formLabels(t) {
|
|
|
1542
1697
|
};
|
|
1543
1698
|
}
|
|
1544
1699
|
function settingsForm(scope) {
|
|
1545
|
-
const form = new
|
|
1700
|
+
const form = new import_dsh_client_ui_primitives2.SettingsFormModel(scope, [
|
|
1546
1701
|
fileCheckpointingEnabledField(),
|
|
1547
1702
|
autoCleanupEnabledField(),
|
|
1548
|
-
(0,
|
|
1703
|
+
(0, import_dsh_client_ui_primitives2.settingsNumberField)("autoCleanupMaxAgeDays")
|
|
1549
1704
|
]);
|
|
1550
1705
|
return {
|
|
1551
1706
|
form,
|
|
@@ -1565,7 +1720,7 @@ function SettingsCard(props) {
|
|
|
1565
1720
|
const checkpointing = state.checkpointingEnabled.text === "true";
|
|
1566
1721
|
const cleanupEnabled = state.enabled.text === "true";
|
|
1567
1722
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1568
|
-
|
|
1723
|
+
import_dsh_client_ui_primitives2.SettingsForm,
|
|
1569
1724
|
{
|
|
1570
1725
|
labels: formLabels(t),
|
|
1571
1726
|
state,
|
|
@@ -1576,7 +1731,7 @@ function SettingsCard(props) {
|
|
|
1576
1731
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dsh-rewind-settings-toggle-row", children: [
|
|
1577
1732
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dsh-rewind-settings-toggle-label", children: t("backup.title") }),
|
|
1578
1733
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1579
|
-
|
|
1734
|
+
import_dsh_client_ui_primitives2.Switch,
|
|
1580
1735
|
{
|
|
1581
1736
|
checked: checkpointing,
|
|
1582
1737
|
label: t("backup.title"),
|
|
@@ -1594,7 +1749,7 @@ function SettingsCard(props) {
|
|
|
1594
1749
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dsh-rewind-settings-toggle-row", children: [
|
|
1595
1750
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dsh-rewind-settings-toggle-label", children: t("cleanup.auto") }),
|
|
1596
1751
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1597
|
-
|
|
1752
|
+
import_dsh_client_ui_primitives2.Switch,
|
|
1598
1753
|
{
|
|
1599
1754
|
checked: cleanupEnabled,
|
|
1600
1755
|
label: t("cleanup.auto"),
|
|
@@ -1608,7 +1763,7 @@ function SettingsCard(props) {
|
|
|
1608
1763
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "dsh-rewind-settings-hint", children: t(cleanupEnabled ? "cleanup.auto.on" : "cleanup.auto.off") })
|
|
1609
1764
|
] }),
|
|
1610
1765
|
cleanupEnabled ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1611
|
-
|
|
1766
|
+
import_dsh_client_ui_primitives2.SettingsValueField,
|
|
1612
1767
|
{
|
|
1613
1768
|
id: "dsh-rewind-cleanup-maxage",
|
|
1614
1769
|
label: t("cleanup.maxAge"),
|
|
@@ -1653,6 +1808,7 @@ function apply(ctx) {
|
|
|
1653
1808
|
style.dataset.plugin = PLUGIN_PACKAGE;
|
|
1654
1809
|
style.textContent = STYLE;
|
|
1655
1810
|
document.head.appendChild(style);
|
|
1811
|
+
installChatViewVisibility(ctx);
|
|
1656
1812
|
const sessionOf = (sessionId) => ctx.sessions.binding(sessionId)?.session;
|
|
1657
1813
|
const isMainViewSession = (sessionId) => (ctx.sessions.list.getSnapshot().byId[sessionId]?.retainedBy.mainView ?? 0) > 0;
|
|
1658
1814
|
const subscribeLocale = (cb) => ctx.locale.subscribe(cb);
|