dsh-desktop-enhance 0.2.0 → 0.2.2
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.md +19 -5
- package/lib/client.js +476 -4
- package/lib/index.d.ts +2 -0
- package/lib/index.js +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# dsh-desktop-enhance
|
|
2
2
|
|
|
3
|
-
为 **DeepSeek Harness 桌面版**(DSH Desktop `0.2.0-rc.2
|
|
3
|
+
为 **DeepSeek Harness 桌面版**(DSH Desktop `0.2.0-rc.2`)补五个界面能力的插件。**自用**。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 五个功能
|
|
6
6
|
|
|
7
7
|
### 页内查找
|
|
8
8
|
|
|
@@ -53,7 +53,7 @@ Web 版(浏览器里打开的那种)键位是 **`Cmd+Shift+.`** —— `Cmd+
|
|
|
53
53
|
- 建议只取**纯文本**;斜杠开头的建议如果在当前会话里不存在,直接丢掉,点了不会报错
|
|
54
54
|
- 切到别的会话再切回来**不会重复问** —— 每一轮只打一次调用,不多花
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
代价要说在前面:**这是五个功能里唯一会花钱的** —— 每轮结束都会打**一次**模型调用。关掉这个开关就完全不打。
|
|
57
57
|
|
|
58
58
|
#### 建议用哪个模型、哪档推理(可调,**建议调**)
|
|
59
59
|
|
|
@@ -76,6 +76,20 @@ Web 版(浏览器里打开的那种)键位是 **`Cmd+Shift+.`** —— `Cmd+
|
|
|
76
76
|
|
|
77
77
|
改坏了有「恢复默认」一键还原。与出厂模板**一字不差**时会存成空串(也就是「用默认」),所以恢复默认之后配置是干净的。
|
|
78
78
|
|
|
79
|
+
|
|
80
|
+
### 每步耗时
|
|
81
|
+
|
|
82
|
+
进程里每一步**几点开始的、花了多久**,直接跟在这一行的文字后面(`14:32 · 23s`):
|
|
83
|
+
|
|
84
|
+
- **折叠起来的过程组头**上显示**整组**的跨度(从第一步开始到最后一步结束,中间模型思考的等待也算在内),开始时刻是**第一个成员**起步的那一刻
|
|
85
|
+
- **展开以后**每一行显示**它自己**那一段,紧跟在行标题后面:工具调用是「派发 → 拿到结果」,思考行是**纯推理那一段**(不含写正文的时间)
|
|
86
|
+
- 数字与同一行的文字**同色同字号**
|
|
87
|
+
- 正在跑的那一行**每秒更新**(和宿主自己那句「深度求索中,用时 X」一样在跳),跑完就固定住、不再跳。**思考行是例外**:推理的起止要等这一步说完才知道,所以它在那一趟结束前不显示数字 —— 这样就不会先跳一个数、说完再往回缩
|
|
88
|
+
|
|
89
|
+
因为数字紧跟标题、且是行内内容,长摘要照常省略号截断、不会被压住,数字也不会被甩到行尾。开始时刻只到分钟(本地时钟)。耗时分档:不足 1 秒写毫秒(`59ms`),1~10 秒写一位小数(`3.8s`),再往上写 `42s` / `2m02s` / `1h20m`。
|
|
90
|
+
|
|
91
|
+
算不出精确区间的位置**不显示数字**,不会拿一个 `0s` 糊上去。
|
|
92
|
+
|
|
79
93
|
## 安装
|
|
80
94
|
|
|
81
95
|
从 npm 装:
|
|
@@ -109,11 +123,11 @@ dsh plugin --profile desktop update dsh-desktop-enhance
|
|
|
109
123
|
|
|
110
124
|
## 开关
|
|
111
125
|
|
|
112
|
-
|
|
126
|
+
五个功能各有一个开关,在**本插件自己的页面**上:
|
|
113
127
|
|
|
114
128
|
> 侧栏 **插件** → 插件列表里选中 **`dsh-desktop-enhance`** → 页面里的 **「UI 增强」** 一栏
|
|
115
129
|
|
|
116
|
-
|
|
130
|
+
五个开关:**页内查找** / **轮次编号** / **压缩行高亮** / **建议** / **每步耗时**。默认全开,装完与之前行为一致,除非你自己去关。
|
|
117
131
|
|
|
118
132
|
「建议」关掉时,它那三个参数(模型 / 推理强度 / 指令模板)也会一并收起 —— 功能关着时它们不起作用。
|
|
119
133
|
|
package/lib/client.js
CHANGED
|
@@ -29,6 +29,8 @@ window.__ModuleLoader__.load({
|
|
|
29
29
|
"settings.compactionRow.hint": "上下文压缩那一行不再折叠隐藏,并显示为醒目的居中胶囊",
|
|
30
30
|
"settings.suggest": "建议",
|
|
31
31
|
"settings.suggest.hint": "每轮结束后问一次模型,把 1 到 3 条可能的下一轮提示词摆在输入框上方,点一下就写进草稿",
|
|
32
|
+
"settings.stepDuration": "每步耗时",
|
|
33
|
+
"settings.stepDuration.hint": "紧跟每一行的文字显示这一步的开始时刻与耗时(如 14:32 · 23s):过程组头是整组、展开后的工具调用与思考行是它自己那一段;正在跑的那一行每秒更新",
|
|
32
34
|
"settings.suggestModel": "建议用哪个模型",
|
|
33
35
|
"settings.suggestModel.hint": "留空则跟随当前会话的模型;建议选一个非推理的轻量模型,否则每条建议都要等它想完",
|
|
34
36
|
"settings.suggestModel.follow": "跟随当前会话",
|
|
@@ -73,6 +75,8 @@ window.__ModuleLoader__.load({
|
|
|
73
75
|
"settings.compactionRow.hint": "Keeps the context-compaction row unfolded and shows it as a prominent centred capsule",
|
|
74
76
|
"settings.suggest": "Suggestions",
|
|
75
77
|
"settings.suggest.hint": "Asks the model once per turn and offers 1–3 likely next-round prompts above the composer; a click writes one into your draft",
|
|
78
|
+
"settings.stepDuration": "Step durations",
|
|
79
|
+
"settings.stepDuration.hint": "Shows when each step started and how long it took, right after that row’s own text (e.g. 14:32 · 23s): the whole group on a process-group header, its own span on every expanded tool call and thinking row; running rows update every second",
|
|
76
80
|
"settings.suggestModel": "Model for suggestions",
|
|
77
81
|
"settings.suggestModel.hint": "Empty follows the current session model. Prefer a lightweight non-reasoning model, or every suggestion waits for it to finish thinking",
|
|
78
82
|
"settings.suggestModel.follow": "Follow the current session",
|
|
@@ -356,13 +360,15 @@ window.__ModuleLoader__.load({
|
|
|
356
360
|
findBar: "data-desktop-enhance-off-find-bar",
|
|
357
361
|
turnPrefix: "data-desktop-enhance-off-turn-prefix",
|
|
358
362
|
compactionRow: "data-desktop-enhance-off-compaction-row",
|
|
359
|
-
suggest: "data-desktop-enhance-off-suggest"
|
|
363
|
+
suggest: "data-desktop-enhance-off-suggest",
|
|
364
|
+
stepDuration: "data-desktop-enhance-off-step-duration"
|
|
360
365
|
};
|
|
361
366
|
const FIELDS = [
|
|
362
367
|
"findBar",
|
|
363
368
|
"turnPrefix",
|
|
364
369
|
"compactionRow",
|
|
365
|
-
"suggest"
|
|
370
|
+
"suggest",
|
|
371
|
+
"stepDuration"
|
|
366
372
|
];
|
|
367
373
|
const ALL_FIELDS = [...FIELDS, ...TEXT_FIELDS];
|
|
368
374
|
function flagOn(value, field) {
|
|
@@ -980,6 +986,455 @@ window.__ModuleLoader__.load({
|
|
|
980
986
|
]);
|
|
981
987
|
}
|
|
982
988
|
//#endregion
|
|
989
|
+
//#region src/client/timing/index.ts
|
|
990
|
+
function finite(value) {
|
|
991
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
992
|
+
}
|
|
993
|
+
function text(value) {
|
|
994
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
995
|
+
}
|
|
996
|
+
function record(value) {
|
|
997
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
998
|
+
}
|
|
999
|
+
function parseNodeKey(key) {
|
|
1000
|
+
const colon = key.indexOf(":");
|
|
1001
|
+
if (colon <= 0) return null;
|
|
1002
|
+
const length = Number(key.slice(0, colon));
|
|
1003
|
+
if (!Number.isSafeInteger(length) || length <= 0) return null;
|
|
1004
|
+
const kind = key.slice(colon + 1, colon + 1 + length);
|
|
1005
|
+
const id = key.slice(colon + 1 + length);
|
|
1006
|
+
if (id === "") return null;
|
|
1007
|
+
return {
|
|
1008
|
+
kind,
|
|
1009
|
+
id
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
function parseStepId(id) {
|
|
1013
|
+
const split = id.indexOf(":");
|
|
1014
|
+
if (split <= 0) return null;
|
|
1015
|
+
const turn = id.slice(0, split);
|
|
1016
|
+
const step = id.slice(split + 1);
|
|
1017
|
+
if (!/^\d+$/.test(turn) || !/^\d+$/.test(step)) return null;
|
|
1018
|
+
return {
|
|
1019
|
+
turn,
|
|
1020
|
+
step
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
function buildTimingIndex(events) {
|
|
1024
|
+
const tools = new Map();
|
|
1025
|
+
const steps = new Map();
|
|
1026
|
+
const reasoning = new Map();
|
|
1027
|
+
const pendingEnds = new Map();
|
|
1028
|
+
for (const raw of events) {
|
|
1029
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
1030
|
+
const event = raw;
|
|
1031
|
+
const time = finite(event.time);
|
|
1032
|
+
if (time === void 0) continue;
|
|
1033
|
+
const data = record(event.data);
|
|
1034
|
+
if (data === null) continue;
|
|
1035
|
+
const type = event.type;
|
|
1036
|
+
if (type === "tool/call") {
|
|
1037
|
+
const callId = text(data.callId);
|
|
1038
|
+
if (callId === void 0) continue;
|
|
1039
|
+
opened(tools, callId, time);
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
if (type === "tool/result") {
|
|
1043
|
+
const callId = resultCallId(data);
|
|
1044
|
+
if (callId === void 0) continue;
|
|
1045
|
+
if (isReplay(event)) continue;
|
|
1046
|
+
closed(tools, callId, time);
|
|
1047
|
+
continue;
|
|
1048
|
+
}
|
|
1049
|
+
if (type === "assistant/message") {
|
|
1050
|
+
if (isReplay(event)) continue;
|
|
1051
|
+
const at = coordinates(data);
|
|
1052
|
+
if (at === void 0 || at.step === void 0) continue;
|
|
1053
|
+
const key = at.turn + ":" + at.step;
|
|
1054
|
+
const span = reasoningSpan(data);
|
|
1055
|
+
if (span === void 0) continue;
|
|
1056
|
+
const found = reasoning.get(key);
|
|
1057
|
+
if (found === void 0) reasoning.set(key, {
|
|
1058
|
+
startedAt: span.startedAt,
|
|
1059
|
+
endedAt: span.endedAt
|
|
1060
|
+
});
|
|
1061
|
+
else {
|
|
1062
|
+
if (span.startedAt < found.startedAt) found.startedAt = span.startedAt;
|
|
1063
|
+
if (found.endedAt === void 0 || span.endedAt > found.endedAt) found.endedAt = span.endedAt;
|
|
1064
|
+
}
|
|
1065
|
+
continue;
|
|
1066
|
+
}
|
|
1067
|
+
if (type === "step/start" || type === "step/end") {
|
|
1068
|
+
const at = coordinates(data);
|
|
1069
|
+
if (at === void 0 || at.step === void 0) continue;
|
|
1070
|
+
const key = at.turn + ":" + at.step;
|
|
1071
|
+
if (type === "step/start") opened(steps, key, time);
|
|
1072
|
+
else closed(steps, key, time);
|
|
1073
|
+
continue;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
function opened(map, key, time) {
|
|
1077
|
+
const found = map.get(key);
|
|
1078
|
+
if (found === void 0) {
|
|
1079
|
+
const span = { startedAt: time };
|
|
1080
|
+
map.set(key, span);
|
|
1081
|
+
attach(key, span);
|
|
1082
|
+
} else if (found.startedAt > time) found.startedAt = time;
|
|
1083
|
+
}
|
|
1084
|
+
function closed(map, key, time) {
|
|
1085
|
+
const found = map.get(key);
|
|
1086
|
+
if (found === void 0) {
|
|
1087
|
+
const held = pendingEnds.get(key);
|
|
1088
|
+
if (held === void 0 || held < time) pendingEnds.set(key, time);
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
if (found.endedAt === void 0 || found.endedAt < time) found.endedAt = time;
|
|
1092
|
+
}
|
|
1093
|
+
function attach(key, span) {
|
|
1094
|
+
const held = pendingEnds.get(key);
|
|
1095
|
+
if (held === void 0) return;
|
|
1096
|
+
span.endedAt = held;
|
|
1097
|
+
pendingEnds.delete(key);
|
|
1098
|
+
}
|
|
1099
|
+
function read(span, at) {
|
|
1100
|
+
if (span === void 0) return void 0;
|
|
1101
|
+
const end = span.endedAt;
|
|
1102
|
+
if (end === void 0) {
|
|
1103
|
+
const now = finite(at);
|
|
1104
|
+
if (now === void 0) return void 0;
|
|
1105
|
+
return {
|
|
1106
|
+
ms: Math.max(0, now - span.startedAt),
|
|
1107
|
+
running: true,
|
|
1108
|
+
startedAt: span.startedAt
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
return {
|
|
1112
|
+
ms: Math.max(0, end - span.startedAt),
|
|
1113
|
+
running: false,
|
|
1114
|
+
startedAt: span.startedAt
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
function spanOf(nodeKey) {
|
|
1118
|
+
const parsed = parseNodeKey(nodeKey);
|
|
1119
|
+
if (parsed === null) return void 0;
|
|
1120
|
+
if (parsed.kind === "tool-call") return tools.get(parsed.id);
|
|
1121
|
+
if (parsed.kind === "assistant-step") {
|
|
1122
|
+
const at = parseStepId(parsed.id);
|
|
1123
|
+
return at === null ? void 0 : steps.get(at.turn + ":" + at.step);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
return {
|
|
1127
|
+
tool: (callId, at) => read(tools.get(callId), at),
|
|
1128
|
+
llm: (turn, step) => {
|
|
1129
|
+
return read(reasoning.get(turn + ":" + step), 0);
|
|
1130
|
+
},
|
|
1131
|
+
group: (nodeKeys, at) => {
|
|
1132
|
+
let start;
|
|
1133
|
+
let end;
|
|
1134
|
+
let open = false;
|
|
1135
|
+
let seen = false;
|
|
1136
|
+
for (const key of nodeKeys) {
|
|
1137
|
+
const span = spanOf(key);
|
|
1138
|
+
if (span === void 0) continue;
|
|
1139
|
+
seen = true;
|
|
1140
|
+
if (start === void 0 || span.startedAt < start) start = span.startedAt;
|
|
1141
|
+
if (span.endedAt === void 0) open = true;
|
|
1142
|
+
else if (end === void 0 || span.endedAt > end) end = span.endedAt;
|
|
1143
|
+
}
|
|
1144
|
+
if (!seen || start === void 0) return void 0;
|
|
1145
|
+
if (open) {
|
|
1146
|
+
const now = finite(at);
|
|
1147
|
+
if (now === void 0) return void 0;
|
|
1148
|
+
return {
|
|
1149
|
+
ms: Math.max(0, (end === void 0 ? now : Math.max(end, now)) - start),
|
|
1150
|
+
running: true,
|
|
1151
|
+
startedAt: start
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
if (end === void 0) return void 0;
|
|
1155
|
+
return {
|
|
1156
|
+
ms: Math.max(0, end - start),
|
|
1157
|
+
running: false,
|
|
1158
|
+
startedAt: start
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
function isReplay(event) {
|
|
1164
|
+
return event.surfaceOp !== void 0 && event.surfaceOp !== "append";
|
|
1165
|
+
}
|
|
1166
|
+
function resultCallId(data) {
|
|
1167
|
+
const message = record(data.message);
|
|
1168
|
+
const source = message === null ? null : record(message.source);
|
|
1169
|
+
if (source === null || source.kind !== "tool") return void 0;
|
|
1170
|
+
return text(source.callId);
|
|
1171
|
+
}
|
|
1172
|
+
function reasoningSpan(data) {
|
|
1173
|
+
const stream = data.stream;
|
|
1174
|
+
if (!Array.isArray(stream)) return void 0;
|
|
1175
|
+
let startedAt;
|
|
1176
|
+
let endedAt;
|
|
1177
|
+
for (const entry of stream) {
|
|
1178
|
+
const chunk = record(entry);
|
|
1179
|
+
if (chunk === null || chunk.type !== "chunk") continue;
|
|
1180
|
+
const inner = record(chunk.chunk);
|
|
1181
|
+
if (inner === null) continue;
|
|
1182
|
+
const time = finite(chunk.time);
|
|
1183
|
+
if (time === void 0) continue;
|
|
1184
|
+
if (inner.type === "block-start") {
|
|
1185
|
+
if (inner.blockType !== "reasoning") continue;
|
|
1186
|
+
if (startedAt === void 0 || time < startedAt) startedAt = time;
|
|
1187
|
+
continue;
|
|
1188
|
+
}
|
|
1189
|
+
if (inner.type === "block-end") {
|
|
1190
|
+
const block = record(inner.block);
|
|
1191
|
+
if (block === null || block.type !== "reasoning") continue;
|
|
1192
|
+
if (endedAt === void 0 || time > endedAt) endedAt = time;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
if (startedAt === void 0 || endedAt === void 0 || endedAt < startedAt) return void 0;
|
|
1196
|
+
return {
|
|
1197
|
+
startedAt,
|
|
1198
|
+
endedAt
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
function coordinates(data) {
|
|
1202
|
+
const turn = data.turn;
|
|
1203
|
+
if (typeof turn !== "number" || !Number.isSafeInteger(turn)) return void 0;
|
|
1204
|
+
const step = data.step;
|
|
1205
|
+
if (typeof step !== "number" || !Number.isSafeInteger(step)) return { turn };
|
|
1206
|
+
return {
|
|
1207
|
+
turn,
|
|
1208
|
+
step
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
function formatDuration(ms) {
|
|
1212
|
+
if (!Number.isFinite(ms) || ms < 0) return "";
|
|
1213
|
+
const rounded = Math.round(ms);
|
|
1214
|
+
if (rounded < 1e3) return rounded + "ms";
|
|
1215
|
+
const total = Math.floor(rounded / 1e3);
|
|
1216
|
+
if (total < 10) return (Math.floor(rounded / 100) / 10).toFixed(1) + "s";
|
|
1217
|
+
if (total < 60) return total + "s";
|
|
1218
|
+
const minutes = Math.floor(total / 60);
|
|
1219
|
+
if (minutes < 60) return minutes + "m" + String(total % 60).padStart(2, "0") + "s";
|
|
1220
|
+
return Math.floor(minutes / 60) + "h" + String(minutes % 60).padStart(2, "0") + "m";
|
|
1221
|
+
}
|
|
1222
|
+
function formatClock(at) {
|
|
1223
|
+
if (!Number.isFinite(at) || at < 0) return "";
|
|
1224
|
+
const date = new Date(at);
|
|
1225
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
1226
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
1227
|
+
return hours + ":" + minutes;
|
|
1228
|
+
}
|
|
1229
|
+
function formatTiming(timing) {
|
|
1230
|
+
const duration = formatDuration(timing.ms);
|
|
1231
|
+
if (duration === "") return "";
|
|
1232
|
+
const clock = formatClock(timing.startedAt);
|
|
1233
|
+
return clock === "" ? duration : clock + " · " + duration;
|
|
1234
|
+
}
|
|
1235
|
+
//#endregion
|
|
1236
|
+
//#region src/client/timing/dom.ts
|
|
1237
|
+
const DURATION_ATTR = "data-desktop-enhance-duration";
|
|
1238
|
+
const CALL_ROW = "[data-chat-call-id]";
|
|
1239
|
+
const THINK_ROW = "[data-variant=\"think\"]";
|
|
1240
|
+
const FIRST_LINE = "[data-disclosure-row], [data-sample]";
|
|
1241
|
+
const SEPARATOR = "[data-shimmer-decoration]";
|
|
1242
|
+
function eventsOf(entries) {
|
|
1243
|
+
const out = [];
|
|
1244
|
+
for (const entry of entries) {
|
|
1245
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
1246
|
+
const record = entry;
|
|
1247
|
+
if (record.type !== "event") continue;
|
|
1248
|
+
if (typeof record.event !== "object" || record.event === null) continue;
|
|
1249
|
+
out.push(record.event);
|
|
1250
|
+
}
|
|
1251
|
+
return out;
|
|
1252
|
+
}
|
|
1253
|
+
function memberTiming(index, nodeKey, at) {
|
|
1254
|
+
const parsed = parseNodeKey(nodeKey);
|
|
1255
|
+
if (parsed === null) return void 0;
|
|
1256
|
+
if (parsed.kind === "tool-call") return index.tool(parsed.id, at);
|
|
1257
|
+
if (parsed.kind === "assistant-step") {
|
|
1258
|
+
const step = parseStepId(parsed.id);
|
|
1259
|
+
if (step === null) return void 0;
|
|
1260
|
+
return index.llm(Number(step.turn), Number(step.step));
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
function callTiming(index, row, at) {
|
|
1264
|
+
const callId = row.getAttribute("data-chat-call-id");
|
|
1265
|
+
if (callId === null || callId === "") return void 0;
|
|
1266
|
+
return index.tool(callId, at);
|
|
1267
|
+
}
|
|
1268
|
+
function thinkTiming(index, row, at) {
|
|
1269
|
+
const nodeKey = row.closest("[data-chat-node-key]")?.getAttribute("data-chat-node-key");
|
|
1270
|
+
if (typeof nodeKey !== "string" || nodeKey === "") return void 0;
|
|
1271
|
+
return memberTiming(index, nodeKey, at);
|
|
1272
|
+
}
|
|
1273
|
+
function titleOf(row) {
|
|
1274
|
+
const line = row.querySelector(FIRST_LINE);
|
|
1275
|
+
if (line === null) return null;
|
|
1276
|
+
const separator = line.querySelector(SEPARATOR);
|
|
1277
|
+
const before = separator === null ? null : separator.previousElementSibling;
|
|
1278
|
+
if (before !== null) return before;
|
|
1279
|
+
return firstTextLeaf(line);
|
|
1280
|
+
}
|
|
1281
|
+
function ownsText(element) {
|
|
1282
|
+
for (const node of Array.from(element.childNodes)) if (node.nodeType === 3 && (node.nodeValue ?? "").trim() !== "") return true;
|
|
1283
|
+
return false;
|
|
1284
|
+
}
|
|
1285
|
+
function firstTextLeaf(root) {
|
|
1286
|
+
for (const child of Array.from(root.children)) {
|
|
1287
|
+
const ns = child.namespaceURI;
|
|
1288
|
+
if (typeof ns === "string" && ns.includes("svg")) continue;
|
|
1289
|
+
if (ownsText(child)) return child;
|
|
1290
|
+
const deeper = firstTextLeaf(child);
|
|
1291
|
+
if (deeper !== null) return deeper;
|
|
1292
|
+
}
|
|
1293
|
+
return null;
|
|
1294
|
+
}
|
|
1295
|
+
function writeTiming(element, timing) {
|
|
1296
|
+
const text = timing === void 0 ? "" : formatTiming(timing);
|
|
1297
|
+
if (text === "") {
|
|
1298
|
+
if (element.hasAttribute("data-desktop-enhance-duration")) element.removeAttribute(DURATION_ATTR);
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
if (element.getAttribute("data-desktop-enhance-duration") !== text) element.setAttribute(DURATION_ATTR, text);
|
|
1302
|
+
}
|
|
1303
|
+
function groupKeys(group) {
|
|
1304
|
+
const keys = [];
|
|
1305
|
+
for (const member of group.querySelectorAll("[data-chat-node-key]")) {
|
|
1306
|
+
const key = member.getAttribute("data-chat-node-key");
|
|
1307
|
+
if (key !== null && key !== "") keys.push(key);
|
|
1308
|
+
}
|
|
1309
|
+
return keys;
|
|
1310
|
+
}
|
|
1311
|
+
function eachTiming(root, visit, index, at) {
|
|
1312
|
+
for (const group of root.querySelectorAll("[data-step-process]")) {
|
|
1313
|
+
const header = group.querySelector("[data-process-activity]");
|
|
1314
|
+
if (header !== null) visit(header, index.group(groupKeys(group), at));
|
|
1315
|
+
}
|
|
1316
|
+
for (const row of root.querySelectorAll(CALL_ROW)) visit(titleOf(row), callTiming(index, row, at));
|
|
1317
|
+
for (const row of root.querySelectorAll(THINK_ROW)) visit(titleOf(row), thinkTiming(index, row, at));
|
|
1318
|
+
}
|
|
1319
|
+
function syncTimings(root, index, at) {
|
|
1320
|
+
let touched = 0;
|
|
1321
|
+
eachTiming(root, (element, timing) => {
|
|
1322
|
+
if (element === null) return;
|
|
1323
|
+
writeTiming(element, timing);
|
|
1324
|
+
touched += 1;
|
|
1325
|
+
}, index, at);
|
|
1326
|
+
return touched;
|
|
1327
|
+
}
|
|
1328
|
+
function anyRunning(root, index, at) {
|
|
1329
|
+
let running = false;
|
|
1330
|
+
eachTiming(root, (_element, timing) => {
|
|
1331
|
+
if (timing?.running === true) running = true;
|
|
1332
|
+
}, index, at);
|
|
1333
|
+
return running;
|
|
1334
|
+
}
|
|
1335
|
+
function conversation() {
|
|
1336
|
+
const root = globalThis.document.querySelector("[data-conversation-session]");
|
|
1337
|
+
if (root === null) return null;
|
|
1338
|
+
const sessionId = root.getAttribute("data-conversation-session");
|
|
1339
|
+
if (sessionId === null || sessionId === "") return null;
|
|
1340
|
+
return {
|
|
1341
|
+
root,
|
|
1342
|
+
sessionId
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
function installTimings(ctx, isOn, getSessions, now = () => globalThis.Date.now()) {
|
|
1346
|
+
let retained = null;
|
|
1347
|
+
let unsubscribe = null;
|
|
1348
|
+
let sessionId = null;
|
|
1349
|
+
let index = buildTimingIndex([]);
|
|
1350
|
+
let timer = null;
|
|
1351
|
+
const retime = (running) => {
|
|
1352
|
+
if (running) {
|
|
1353
|
+
if (timer === null) timer = globalThis.setInterval(() => {
|
|
1354
|
+
const found = conversation();
|
|
1355
|
+
if (found === null) return;
|
|
1356
|
+
syncTimings(found.root, index, now());
|
|
1357
|
+
}, 1e3);
|
|
1358
|
+
} else if (timer !== null) {
|
|
1359
|
+
globalThis.clearInterval(timer);
|
|
1360
|
+
timer = null;
|
|
1361
|
+
}
|
|
1362
|
+
};
|
|
1363
|
+
const detach = () => {
|
|
1364
|
+
if (unsubscribe !== null) {
|
|
1365
|
+
unsubscribe();
|
|
1366
|
+
unsubscribe = null;
|
|
1367
|
+
}
|
|
1368
|
+
if (retained !== null) {
|
|
1369
|
+
retained.release();
|
|
1370
|
+
retained = null;
|
|
1371
|
+
}
|
|
1372
|
+
sessionId = null;
|
|
1373
|
+
index = buildTimingIndex([]);
|
|
1374
|
+
};
|
|
1375
|
+
const paint = (root) => {
|
|
1376
|
+
syncTimings(root, index, now());
|
|
1377
|
+
retime(anyRunning(root, index, now()));
|
|
1378
|
+
};
|
|
1379
|
+
const attach = (id, root) => {
|
|
1380
|
+
const sessions = getSessions();
|
|
1381
|
+
if (sessions === null || sessions === void 0 || typeof sessions.retain !== "function") return;
|
|
1382
|
+
let reference;
|
|
1383
|
+
try {
|
|
1384
|
+
reference = sessions.retain(id, { source: NS });
|
|
1385
|
+
} catch {
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
retained = reference;
|
|
1389
|
+
sessionId = id;
|
|
1390
|
+
const source = reference.binding.eventSource;
|
|
1391
|
+
const rebuild = () => {
|
|
1392
|
+
index = isOn() ? buildTimingIndex(eventsOf(source.getSnapshot().entries ?? [])) : buildTimingIndex([]);
|
|
1393
|
+
paint(root);
|
|
1394
|
+
};
|
|
1395
|
+
unsubscribe = source.subscribe(rebuild);
|
|
1396
|
+
rebuild();
|
|
1397
|
+
};
|
|
1398
|
+
const sync = () => {
|
|
1399
|
+
const found = conversation();
|
|
1400
|
+
if (found === null) {
|
|
1401
|
+
retime(false);
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
if (!isOn()) {
|
|
1405
|
+
detach();
|
|
1406
|
+
retime(false);
|
|
1407
|
+
syncTimings(found.root, buildTimingIndex([]), now());
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
if (found.sessionId !== sessionId) {
|
|
1411
|
+
detach();
|
|
1412
|
+
attach(found.sessionId, found.root);
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
paint(found.root);
|
|
1416
|
+
};
|
|
1417
|
+
ctx.effect(() => {
|
|
1418
|
+
const observer = new globalThis.MutationObserver(() => {
|
|
1419
|
+
sync();
|
|
1420
|
+
});
|
|
1421
|
+
observer.observe(globalThis.document.documentElement, {
|
|
1422
|
+
childList: true,
|
|
1423
|
+
subtree: true
|
|
1424
|
+
});
|
|
1425
|
+
return () => {
|
|
1426
|
+
observer.disconnect();
|
|
1427
|
+
if (timer !== null) {
|
|
1428
|
+
globalThis.clearInterval(timer);
|
|
1429
|
+
timer = null;
|
|
1430
|
+
}
|
|
1431
|
+
detach();
|
|
1432
|
+
};
|
|
1433
|
+
}, "desktop-enhance: timing observer");
|
|
1434
|
+
sync();
|
|
1435
|
+
return { refresh: sync };
|
|
1436
|
+
}
|
|
1437
|
+
//#endregion
|
|
983
1438
|
//#region src/client/turn/prefix.ts
|
|
984
1439
|
function parseTurnNumber(label) {
|
|
985
1440
|
if (typeof label !== "string") return null;
|
|
@@ -1485,7 +1940,7 @@ window.__ModuleLoader__.load({
|
|
|
1485
1940
|
}
|
|
1486
1941
|
//#endregion
|
|
1487
1942
|
//#region \0dsh-desktop-enhance-css:/Users/lijiechengbj/projects/AI-agents/dsh-desktop-enhance/src/client/styles/enhance.css.mjs
|
|
1488
|
-
var enhance_css_default = "\n\n:root:not([data-desktop-enhance-off-compaction-row])\n [hidden=\"until-found\"]:has([data-chat-flow-kind=\"compaction\"]) {\n content-visibility: visible !important;\n}\n\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"compaction\"][hidden=\"until-found\"] {\n content-visibility: visible !important;\n}\n:root:not([data-desktop-enhance-off-compaction-row])\n [hidden=\"until-found\"]:has([data-chat-flow-kind=\"compaction\"])\n [data-turn-process-member=\"true\"]:not([data-chat-flow-kind=\"compaction\"]) {\n display: none !important;\n}\n\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-step-process=\"true\"][hidden=\"until-found\"]:has([data-chat-flow-kind=\"compaction\"])\n > div:has(> [data-process-activity]) {\n display: none !important;\n}\n\n\n:root:not([data-desktop-enhance-off-compaction-row]) [data-chat-flow-kind=\"compaction\"],\n:root:not([data-desktop-enhance-off-compaction-row]) [data-chat-flow-kind=\"manual-compaction\"] {\n padding: 6px 0 !important;\n}\n\n:root:not([data-desktop-enhance-off-compaction-row]) [data-chat-flow-kind=\"compaction\"] button,\n:root:not([data-desktop-enhance-off-compaction-row]) [data-chat-flow-kind=\"manual-compaction\"] button {\n width: fit-content !important;\n margin: 0 auto !important;\n height: auto !important;\n min-height: 28px;\n padding: 0 14px !important;\n justify-content: center !important;\n background: var(--dsw-alias-state-warn-tertiary) !important;\n border-radius: 999px !important;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--dsw-alias-state-warn-primary) 45%, transparent);\n color: var(--dsw-alias-state-warn-label) !important;\n}\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"compaction\"] button:hover:not(:disabled),\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"manual-compaction\"] button:hover:not(:disabled) {\n background: var(--dsw-alias-state-warn-secondary) !important;\n}\n\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"compaction\"] button:has([data-compaction-disclosure=\"expanded\"]),\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"manual-compaction\"] button:has([data-compaction-disclosure=\"expanded\"]) {\n width: 100% !important;\n margin: 0 !important;\n border-radius: var(--dsw-radius-sm) !important;\n}\n\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"compaction\"] button > span:not([aria-hidden]):not(:last-child),\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"manual-compaction\"] button > span:not([aria-hidden]):not(:last-child) {\n font-weight: 600;\n}\n\n\n[data-desktop-enhance-reveal] {\n content-visibility: visible !important;\n}\n[hidden=\"until-found\"]:has([data-chat-flow-kind=\"compaction\"])\n [data-turn-process-member=\"true\"][data-desktop-enhance-reveal]:not([data-chat-flow-kind=\"compaction\"]) {\n display: revert !important;\n}\n\n\n:root:not([data-desktop-enhance-off-turn-prefix]) [data-desktop-enhance-turn]::before {\n content: attr(data-desktop-enhance-turn);\n flex: none;\n margin-right: 6px;\n padding: 0 5px;\n border-radius: var(--dsw-radius-xs);\n background: var(--dsw-alias-interactive-bg-hover-solid);\n color: var(--dsw-alias-label-secondary);\n font: var(--dsw-font-xxxs-strong-11);\n}\n\n\n\n:root[data-desktop-enhance-off-find-bar] [data-desktop-enhance-findbar] {\n display: none !important;\n}\n[data-desktop-enhance-findbar] {\n position: absolute;\n top: 12px;\n right: 20px;\n z-index: 30;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n box-shadow: var(--dsw-elevation-panel);\n}\n[data-desktop-enhance-findbar] input {\n width: 200px;\n border: none;\n outline: none;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-s-14);\n}\n[data-desktop-enhance-findbar] input:focus-visible {\n outline: 1px solid var(--dsw-focus-ring-color);\n outline-offset: 2px;\n}\n[data-desktop-enhance-findbar] .count {\n min-width: 44px;\n text-align: right;\n color: var(--dsw-alias-label-tertiary);\n font: var(--dsw-font-xxs-12);\n}\n[data-desktop-enhance-findbar] button {\n display: grid;\n place-items: center;\n width: 22px;\n height: 22px;\n padding: 0;\n border: none;\n border-radius: var(--dsw-radius-xs);\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: var(--dsw-font-s-14);\n}\n[data-desktop-enhance-findbar] button:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n[data-desktop-enhance-findbar] button:disabled {\n opacity: .4;\n cursor: default;\n}\n::highlight(desktop-enhance-find) {\n background-color: var(--dsw-alias-state-warn-tertiary);\n}\n::highlight(desktop-enhance-find-current) {\n background-color: var(--dsw-alias-state-warn-primary);\n color: var(--dsw-alias-label-primary-inverted);\n}\n\n\n[data-desktop-enhance-settings] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px 0;\n}\n[data-desktop-enhance-settings] .de-head-title {\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-s-14);\n font-weight: 600;\n}\n[data-desktop-enhance-settings] .de-head-desc,\n[data-desktop-enhance-settings] .de-desc {\n color: var(--dsw-alias-label-tertiary);\n font: var(--dsw-font-xxs-12);\n}\n[data-desktop-enhance-settings] .de-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n}\n[data-desktop-enhance-settings] .de-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n[data-desktop-enhance-settings] .de-title {\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-s-14);\n}\n\n[data-desktop-enhance-settings] .de-switch {\n position: relative;\n flex: none;\n width: 36px;\n height: 20px;\n padding: 0;\n border: none;\n border-radius: 999px;\n background: var(--dsw-alias-interactive-bg-hover-solid);\n cursor: pointer;\n transition: background .15s;\n}\n[data-desktop-enhance-settings] .de-switch::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--dsw-alias-switch-thumb);\n transition: transform .15s;\n}\n[data-desktop-enhance-settings] .de-switch[aria-checked=\"true\"] {\n background: var(--dsw-alias-state-success-primary);\n}\n[data-desktop-enhance-settings] .de-switch[aria-checked=\"true\"]::after {\n transform: translateX(16px);\n}\n[data-desktop-enhance-settings] .de-switch:disabled {\n opacity: .5;\n cursor: default;\n}\n[data-desktop-enhance-settings] .de-note {\n color: var(--dsw-alias-label-tertiary);\n font: var(--dsw-font-xxs-12);\n}\n[data-desktop-enhance-settings] .de-error {\n color: var(--dsw-alias-state-error-primary);\n font: var(--dsw-font-xxs-12);\n}\n\n\n\n[data-desktop-enhance-settings] .de-suggest-settings {\n display: flex;\n flex-direction: column;\n gap: 12px;\n \n border-top: 1px solid var(--dsw-alias-border-l1);\n margin-top: 4px;\n padding-top: 12px;\n}\n[data-desktop-enhance-settings] .de-item-block {\n align-items: stretch;\n flex-direction: column;\n gap: 6px;\n}\n[data-desktop-enhance-settings] .de-select,\n[data-desktop-enhance-settings] .de-text-input,\n[data-desktop-enhance-settings] .de-textarea {\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-xs-13);\n padding: 6px 8px;\n width: 100%;\n}\n[data-desktop-enhance-settings] .de-select:disabled,\n[data-desktop-enhance-settings] .de-text-input:disabled,\n[data-desktop-enhance-settings] .de-textarea:disabled {\n opacity: .5;\n}\n\n[data-desktop-enhance-settings] .de-textarea {\n font-family: var(--dsw-font-family-mono, ui-monospace, SFMono-Regular, Menlo, monospace);\n line-height: 1.5;\n resize: vertical;\n white-space: pre-wrap;\n}\n[data-desktop-enhance-settings] .de-prompt {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n[data-desktop-enhance-settings] .de-prompt-meta {\n color: var(--dsw-alias-label-tertiary);\n font: var(--dsw-font-xxs-12);\n}\n[data-desktop-enhance-settings] .de-prompt-actions {\n display: flex;\n gap: 8px;\n}\n[data-desktop-enhance-settings] .de-button {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: var(--dsw-font-xxs-12);\n padding: 4px 10px;\n}\n[data-desktop-enhance-settings] .de-button:hover {\n border-color: var(--dsw-alias-border-l2);\n}\n[data-desktop-enhance-settings] .de-button:disabled {\n cursor: default;\n opacity: .5;\n}\n\n\n\n\n:root[data-desktop-enhance-off-suggest] [data-desktop-enhance='suggest'] {\n display: none !important;\n}\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest {\n align-items: center;\n box-sizing: border-box;\n display: flex;\n \n flex-wrap: wrap;\n gap: 6px;\n \n margin: 0 auto 6px;\n max-width: var(--dsh-composer-card-max-width, 100%);\n \n min-width: 0;\n \n padding-left: 14px;\n width: calc(100% - var(--dsh-composer-side-clearance, 0px) - var(--dsh-composer-side-clearance, 0px));\n}\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-head {\n align-items: center;\n display: flex;\n flex: none;\n gap: 2px;\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-title {\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-xs-13);\n font-weight: 500;\n \n white-space: nowrap;\n}\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-close {\n appearance: none;\n background: none;\n border: 0;\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n flex: none;\n font: var(--dsw-font-xxs-12);\n line-height: 1;\n padding: 2px 4px;\n}\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-close:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-row {\n appearance: none;\n align-items: center;\n background: none;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n display: flex;\n flex: 0 1 auto;\n font: var(--dsw-font-xs-13);\n gap: 6px;\n \n max-width: 100%;\n min-width: 0;\n padding: 4px 10px;\n text-align: left;\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-row:hover {\n background: var(--dsw-alias-state-business-tertiary);\n border-color: var(--dsw-alias-state-business-primary);\n color: var(--dsw-alias-state-business-primary);\n transition: background-color .12s ease, border-color .12s ease, color .12s ease;\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-row[data-used='true'] {\n border-color: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-label-secondary);\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-num {\n color: var(--dsw-alias-label-primary);\n flex: none;\n font: var(--dsw-font-xs-13);\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-text {\n max-width: 22ch;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-loading {\n border-style: dashed;\n color: var(--dsw-alias-label-secondary);\n cursor: default;\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-error {\n color: var(--dsw-alias-state-error-primary);\n flex: 1 1 auto;\n font: var(--dsw-font-xxs-12);\n min-width: 0;\n padding: 2px;\n}\n";
|
|
1943
|
+
var enhance_css_default = "\n\n:root:not([data-desktop-enhance-off-compaction-row])\n [hidden=\"until-found\"]:has([data-chat-flow-kind=\"compaction\"]) {\n content-visibility: visible !important;\n}\n\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"compaction\"][hidden=\"until-found\"] {\n content-visibility: visible !important;\n}\n:root:not([data-desktop-enhance-off-compaction-row])\n [hidden=\"until-found\"]:has([data-chat-flow-kind=\"compaction\"])\n [data-turn-process-member=\"true\"]:not([data-chat-flow-kind=\"compaction\"]) {\n display: none !important;\n}\n\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-step-process=\"true\"][hidden=\"until-found\"]:has([data-chat-flow-kind=\"compaction\"])\n > div:has(> [data-process-activity]) {\n display: none !important;\n}\n\n\n:root:not([data-desktop-enhance-off-compaction-row]) [data-chat-flow-kind=\"compaction\"],\n:root:not([data-desktop-enhance-off-compaction-row]) [data-chat-flow-kind=\"manual-compaction\"] {\n padding: 6px 0 !important;\n}\n\n:root:not([data-desktop-enhance-off-compaction-row]) [data-chat-flow-kind=\"compaction\"] button,\n:root:not([data-desktop-enhance-off-compaction-row]) [data-chat-flow-kind=\"manual-compaction\"] button {\n width: fit-content !important;\n margin: 0 auto !important;\n height: auto !important;\n min-height: 28px;\n padding: 0 14px !important;\n justify-content: center !important;\n background: var(--dsw-alias-state-warn-tertiary) !important;\n border-radius: 999px !important;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--dsw-alias-state-warn-primary) 45%, transparent);\n color: var(--dsw-alias-state-warn-label) !important;\n}\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"compaction\"] button:hover:not(:disabled),\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"manual-compaction\"] button:hover:not(:disabled) {\n background: var(--dsw-alias-state-warn-secondary) !important;\n}\n\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"compaction\"] button:has([data-compaction-disclosure=\"expanded\"]),\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"manual-compaction\"] button:has([data-compaction-disclosure=\"expanded\"]) {\n width: 100% !important;\n margin: 0 !important;\n border-radius: var(--dsw-radius-sm) !important;\n}\n\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"compaction\"] button > span:not([aria-hidden]):not(:last-child),\n:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"manual-compaction\"] button > span:not([aria-hidden]):not(:last-child) {\n font-weight: 600;\n}\n\n\n[data-desktop-enhance-reveal] {\n content-visibility: visible !important;\n}\n[hidden=\"until-found\"]:has([data-chat-flow-kind=\"compaction\"])\n [data-turn-process-member=\"true\"][data-desktop-enhance-reveal]:not([data-chat-flow-kind=\"compaction\"]) {\n display: revert !important;\n}\n\n\n:root:not([data-desktop-enhance-off-turn-prefix]) [data-desktop-enhance-turn]::before {\n content: attr(data-desktop-enhance-turn);\n flex: none;\n margin-right: 6px;\n padding: 0 5px;\n border-radius: var(--dsw-radius-xs);\n background: var(--dsw-alias-interactive-bg-hover-solid);\n color: var(--dsw-alias-label-secondary);\n font: var(--dsw-font-xxxs-strong-11);\n}\n\n\n\n:root[data-desktop-enhance-off-find-bar] [data-desktop-enhance-findbar] {\n display: none !important;\n}\n[data-desktop-enhance-findbar] {\n position: absolute;\n top: 12px;\n right: 20px;\n z-index: 30;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n box-shadow: var(--dsw-elevation-panel);\n}\n[data-desktop-enhance-findbar] input {\n width: 200px;\n border: none;\n outline: none;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-s-14);\n}\n[data-desktop-enhance-findbar] input:focus-visible {\n outline: 1px solid var(--dsw-focus-ring-color);\n outline-offset: 2px;\n}\n[data-desktop-enhance-findbar] .count {\n min-width: 44px;\n text-align: right;\n color: var(--dsw-alias-label-tertiary);\n font: var(--dsw-font-xxs-12);\n}\n[data-desktop-enhance-findbar] button {\n display: grid;\n place-items: center;\n width: 22px;\n height: 22px;\n padding: 0;\n border: none;\n border-radius: var(--dsw-radius-xs);\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: var(--dsw-font-s-14);\n}\n[data-desktop-enhance-findbar] button:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n[data-desktop-enhance-findbar] button:disabled {\n opacity: .4;\n cursor: default;\n}\n::highlight(desktop-enhance-find) {\n background-color: var(--dsw-alias-state-warn-tertiary);\n}\n::highlight(desktop-enhance-find-current) {\n background-color: var(--dsw-alias-state-warn-primary);\n color: var(--dsw-alias-label-primary-inverted);\n}\n\n\n[data-desktop-enhance-settings] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px 0;\n}\n[data-desktop-enhance-settings] .de-head-title {\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-s-14);\n font-weight: 600;\n}\n[data-desktop-enhance-settings] .de-head-desc,\n[data-desktop-enhance-settings] .de-desc {\n color: var(--dsw-alias-label-tertiary);\n font: var(--dsw-font-xxs-12);\n}\n[data-desktop-enhance-settings] .de-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n}\n[data-desktop-enhance-settings] .de-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n[data-desktop-enhance-settings] .de-title {\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-s-14);\n}\n\n[data-desktop-enhance-settings] .de-switch {\n position: relative;\n flex: none;\n width: 36px;\n height: 20px;\n padding: 0;\n border: none;\n border-radius: 999px;\n background: var(--dsw-alias-interactive-bg-hover-solid);\n cursor: pointer;\n transition: background .15s;\n}\n[data-desktop-enhance-settings] .de-switch::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--dsw-alias-switch-thumb);\n transition: transform .15s;\n}\n[data-desktop-enhance-settings] .de-switch[aria-checked=\"true\"] {\n background: var(--dsw-alias-state-success-primary);\n}\n[data-desktop-enhance-settings] .de-switch[aria-checked=\"true\"]::after {\n transform: translateX(16px);\n}\n[data-desktop-enhance-settings] .de-switch:disabled {\n opacity: .5;\n cursor: default;\n}\n[data-desktop-enhance-settings] .de-note {\n color: var(--dsw-alias-label-tertiary);\n font: var(--dsw-font-xxs-12);\n}\n[data-desktop-enhance-settings] .de-error {\n color: var(--dsw-alias-state-error-primary);\n font: var(--dsw-font-xxs-12);\n}\n\n\n\n[data-desktop-enhance-settings] .de-suggest-settings {\n display: flex;\n flex-direction: column;\n gap: 12px;\n \n border-top: 1px solid var(--dsw-alias-border-l1);\n margin-top: 4px;\n padding-top: 12px;\n}\n[data-desktop-enhance-settings] .de-item-block {\n align-items: stretch;\n flex-direction: column;\n gap: 6px;\n}\n[data-desktop-enhance-settings] .de-select,\n[data-desktop-enhance-settings] .de-text-input,\n[data-desktop-enhance-settings] .de-textarea {\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-xs-13);\n padding: 6px 8px;\n width: 100%;\n}\n[data-desktop-enhance-settings] .de-select:disabled,\n[data-desktop-enhance-settings] .de-text-input:disabled,\n[data-desktop-enhance-settings] .de-textarea:disabled {\n opacity: .5;\n}\n\n[data-desktop-enhance-settings] .de-textarea {\n font-family: var(--dsw-font-family-mono, ui-monospace, SFMono-Regular, Menlo, monospace);\n line-height: 1.5;\n resize: vertical;\n white-space: pre-wrap;\n}\n[data-desktop-enhance-settings] .de-prompt {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n[data-desktop-enhance-settings] .de-prompt-meta {\n color: var(--dsw-alias-label-tertiary);\n font: var(--dsw-font-xxs-12);\n}\n[data-desktop-enhance-settings] .de-prompt-actions {\n display: flex;\n gap: 8px;\n}\n[data-desktop-enhance-settings] .de-button {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: var(--dsw-font-xxs-12);\n padding: 4px 10px;\n}\n[data-desktop-enhance-settings] .de-button:hover {\n border-color: var(--dsw-alias-border-l2);\n}\n[data-desktop-enhance-settings] .de-button:disabled {\n cursor: default;\n opacity: .5;\n}\n\n\n\n\n:root[data-desktop-enhance-off-suggest] [data-desktop-enhance='suggest'] {\n display: none !important;\n}\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest {\n align-items: center;\n \n background: color-mix(in srgb, var(--dsw-alias-state-business-tertiary) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-business-primary) 20%, transparent);\n border-radius: var(--dsw-radius-md);\n box-sizing: border-box;\n display: flex;\n \n flex-wrap: wrap;\n gap: 6px;\n \n margin: 0 auto 6px;\n max-width: var(--dsh-composer-card-max-width, 100%);\n \n min-width: 0;\n \n padding: 4px 10px 4px 13px;\n width: calc(100% - var(--dsh-composer-side-clearance, 0px) - var(--dsh-composer-side-clearance, 0px));\n}\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-head {\n align-items: center;\n display: flex;\n flex: none;\n gap: 2px;\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-title {\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-xs-13);\n font-weight: 500;\n \n white-space: nowrap;\n}\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-close {\n appearance: none;\n background: none;\n border: 0;\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n flex: none;\n font: var(--dsw-font-xxs-12);\n line-height: 1;\n padding: 2px 4px;\n}\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-close:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-row {\n appearance: none;\n align-items: center;\n background: none;\n \n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-business-primary) 35%, transparent);\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n display: flex;\n flex: 0 1 auto;\n font: var(--dsw-font-xs-13);\n gap: 6px;\n \n max-width: 100%;\n min-width: 0;\n padding: 4px 10px;\n text-align: left;\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-row:hover {\n background: var(--dsw-alias-state-business-tertiary);\n border-color: var(--dsw-alias-state-business-primary);\n color: var(--dsw-alias-state-business-primary);\n transition: background-color .12s ease, border-color .12s ease, color .12s ease;\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-row[data-used='true'] {\n border-color: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-label-secondary);\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-num {\n color: var(--dsw-alias-label-primary);\n flex: none;\n font: var(--dsw-font-xs-13);\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-text {\n max-width: 22ch;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-loading {\n border-style: dashed;\n color: var(--dsw-alias-label-secondary);\n cursor: default;\n}\n\n:root:not([data-desktop-enhance-off-suggest]) .de-suggest-error {\n color: var(--dsw-alias-state-error-primary);\n flex: 1 1 auto;\n font: var(--dsw-font-xxs-12);\n min-width: 0;\n padding: 2px;\n}\n\n\n:root:not([data-desktop-enhance-off-step-duration]) [data-desktop-enhance-duration]::after {\n content: attr(data-desktop-enhance-duration);\n \n margin-left: 8px;\n font-size: inherit;\n line-height: inherit;\n \n font-variant-numeric: tabular-nums;\n color: inherit;\n white-space: nowrap;\n pointer-events: none;\n user-select: none;\n}\n\n:root:not([data-desktop-enhance-off-step-duration])\n [data-desktop-enhance-duration]:has([data-step-process-icon])::after {\n margin-left: 2px;\n}\n";
|
|
1489
1944
|
//#endregion
|
|
1490
1945
|
//#region src/client/index.tsx
|
|
1491
1946
|
const inject = [
|
|
@@ -1558,6 +2013,7 @@ window.__ModuleLoader__.load({
|
|
|
1558
2013
|
}, SettingsRow))), "desktop-enhance: plugin page card");
|
|
1559
2014
|
});
|
|
1560
2015
|
installTurnPrefix(ctx);
|
|
2016
|
+
const timings = installTimings(ctx, () => flagOn(settings.get().value, "stepDuration"), () => ctx.get("sessions"));
|
|
1561
2017
|
const suggestStore = createSuggestStore();
|
|
1562
2018
|
const suggestWatcher = createSuggestWatcher(() => ctx.get("sessions"), suggestStore, {
|
|
1563
2019
|
fetchImpl: globalThis.fetch,
|
|
@@ -1567,6 +2023,7 @@ window.__ModuleLoader__.load({
|
|
|
1567
2023
|
ctx.effect(() => {
|
|
1568
2024
|
const off = settings.subscribe(() => {
|
|
1569
2025
|
suggestWatcher.refresh();
|
|
2026
|
+
timings.refresh();
|
|
1570
2027
|
});
|
|
1571
2028
|
return () => {
|
|
1572
2029
|
off();
|
|
@@ -1697,7 +2154,22 @@ window.__ModuleLoader__.load({
|
|
|
1697
2154
|
ModelPicker,
|
|
1698
2155
|
zh,
|
|
1699
2156
|
en,
|
|
1700
|
-
css: enhance_css_default
|
|
2157
|
+
css: enhance_css_default,
|
|
2158
|
+
buildTimingIndex,
|
|
2159
|
+
formatDuration,
|
|
2160
|
+
formatClock,
|
|
2161
|
+
formatTiming,
|
|
2162
|
+
parseNodeKey,
|
|
2163
|
+
parseStepId,
|
|
2164
|
+
eventsOf,
|
|
2165
|
+
memberTiming,
|
|
2166
|
+
callTiming,
|
|
2167
|
+
thinkTiming,
|
|
2168
|
+
syncTimings,
|
|
2169
|
+
anyRunning,
|
|
2170
|
+
installTimings,
|
|
2171
|
+
DURATION_ATTR,
|
|
2172
|
+
titleOf
|
|
1701
2173
|
};
|
|
1702
2174
|
exports.apply = apply;
|
|
1703
2175
|
exports.inject = inject;
|
package/lib/index.d.ts
CHANGED
|
@@ -96,6 +96,7 @@ export declare const Config: Schema<Schemastery.ObjectS<NoInfer<{
|
|
|
96
96
|
turnPrefix: Schema<boolean, boolean, "volatile-defined">;
|
|
97
97
|
compactionRow: Schema<boolean, boolean, "volatile-defined">;
|
|
98
98
|
suggest: Schema<boolean, boolean, "volatile-defined">;
|
|
99
|
+
stepDuration: Schema<boolean, boolean, "volatile-defined">;
|
|
99
100
|
suggestModel: Schema<string, string, "volatile-defined">;
|
|
100
101
|
suggestReasoning: Schema<string, string, "volatile-defined">;
|
|
101
102
|
suggestPrompt: Schema<string, string, "volatile-defined">;
|
|
@@ -104,6 +105,7 @@ export declare const Config: Schema<Schemastery.ObjectS<NoInfer<{
|
|
|
104
105
|
turnPrefix: Schema<boolean, boolean, "volatile-defined">;
|
|
105
106
|
compactionRow: Schema<boolean, boolean, "volatile-defined">;
|
|
106
107
|
suggest: Schema<boolean, boolean, "volatile-defined">;
|
|
108
|
+
stepDuration: Schema<boolean, boolean, "volatile-defined">;
|
|
107
109
|
suggestModel: Schema<string, string, "volatile-defined">;
|
|
108
110
|
suggestReasoning: Schema<string, string, "volatile-defined">;
|
|
109
111
|
suggestPrompt: Schema<string, string, "volatile-defined">;
|
package/lib/index.js
CHANGED
|
@@ -351,6 +351,7 @@ const Config = Schema.object({
|
|
|
351
351
|
turnPrefix: Schema.boolean().default(true).volatile(),
|
|
352
352
|
compactionRow: Schema.boolean().default(true).volatile(),
|
|
353
353
|
suggest: Schema.boolean().default(true).volatile(),
|
|
354
|
+
stepDuration: Schema.boolean().default(true).volatile(),
|
|
354
355
|
suggestModel: Schema.string().default("").volatile(),
|
|
355
356
|
suggestReasoning: Schema.string().default("").volatile(),
|
|
356
357
|
suggestPrompt: Schema.string().default("").volatile()
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-desktop-enhance",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "DSH Desktop 界面增强:页内查找(Cmd+F
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "DSH Desktop 界面增强:页内查找(Cmd+F)、轮次编号、上下文压缩行常显、建议、每步耗时。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./lib/index.js",
|