dsh-desktop-enhance 0.2.3 → 0.2.5
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 +13 -4
- package/lib/client.js +496 -4
- package/lib/index.d.ts +9 -0
- package/lib/index.js +207 -8
- 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
|
|
|
@@ -90,6 +90,15 @@ Web 版(浏览器里打开的那种)键位是 **`Cmd+Shift+.`** —— `Cmd+
|
|
|
90
90
|
|
|
91
91
|
算不出精确区间的位置**不显示数字**,不会拿一个 `0s` 糊上去。
|
|
92
92
|
|
|
93
|
+
### 会话信息
|
|
94
|
+
|
|
95
|
+
在主对话区右上角悬浮展示一个可折叠的手风琴看板(标题为 **「会话信息」**):
|
|
96
|
+
|
|
97
|
+
- **已注入 Skill 分节**:展示当前会话活跃上下文中已注入的 Skill 列表、触发方式(`用户触发` / `Agent触发`)以及对应的轮次号(`#N`);还没有任何 Skill 时显示 `0` 与「暂无已注入 Skill」提示
|
|
98
|
+
- **点击预览**:点击任意一条 Skill,直接打开宿主内置的右侧栏 Skill 详情预览(`openSkill`)
|
|
99
|
+
- **折叠与展开**:点击顶栏可把整张卡片收起成一枚紧凑胶囊(`会话信息 · Skill N`),点击分节头可单独收起/展开该分节
|
|
100
|
+
- **全量 + 实时**:实时监听前端会话事件流,同时向 Host 查询完整会话日志基线,即使几百轮的长会话只加载了尾部窗口,第 1 轮注入的 Skill 也不会漏掉;被上下文压缩或裁剪替换掉的节点会自动剔除
|
|
101
|
+
|
|
93
102
|
## 安装
|
|
94
103
|
|
|
95
104
|
从 npm 装:
|
|
@@ -123,11 +132,11 @@ dsh plugin --profile desktop update dsh-desktop-enhance
|
|
|
123
132
|
|
|
124
133
|
## 开关
|
|
125
134
|
|
|
126
|
-
|
|
135
|
+
六个功能各有一个开关,在**本插件自己的页面**上:
|
|
127
136
|
|
|
128
137
|
> 侧栏 **插件** → 插件列表里选中 **`dsh-desktop-enhance`** → 页面里的 **「UI 增强」** 一栏
|
|
129
138
|
|
|
130
|
-
|
|
139
|
+
六个开关:**页内查找** / **轮次编号** / **压缩行高亮** / **建议** / **每步耗时** / **会话信息**。默认全开,装完与之前行为一致,除非你自己去关。
|
|
131
140
|
|
|
132
141
|
「建议」关掉时,它那三个参数(模型 / 推理强度 / 指令模板)也会一并收起 —— 功能关着时它们不起作用。
|
|
133
142
|
|
package/lib/client.js
CHANGED
|
@@ -19,6 +19,14 @@ window.__ModuleLoader__.load({
|
|
|
19
19
|
"suggest.loading": "正在想下一轮…",
|
|
20
20
|
"suggest.dismiss": "收起建议",
|
|
21
21
|
"suggest.failed": "没写进输入框(宿主正忙或草稿有冲突),可以再点一次。",
|
|
22
|
+
"sessionInfo.title": "会话信息",
|
|
23
|
+
"sessionInfo.collapse": "收起会话信息",
|
|
24
|
+
"sessionInfo.expand": "展开会话信息",
|
|
25
|
+
"sessionInfo.skills.title": "已注入 Skill",
|
|
26
|
+
"sessionInfo.skills.short": "Skill",
|
|
27
|
+
"sessionInfo.skills.empty": "暂无已注入 Skill",
|
|
28
|
+
"sessionInfo.trigger.user": "用户触发",
|
|
29
|
+
"sessionInfo.trigger.agent": "Agent触发",
|
|
22
30
|
"settings.title": "UI 增强",
|
|
23
31
|
"settings.description": "逐项开关本插件添加的界面增强。关闭后恢复 DSH 原生外观。",
|
|
24
32
|
"settings.findBar": "页内查找",
|
|
@@ -31,6 +39,8 @@ window.__ModuleLoader__.load({
|
|
|
31
39
|
"settings.suggest.hint": "每轮结束后问一次模型,把 1 到 3 条可能的下一轮提示词摆在输入框上方,点一下就写进草稿",
|
|
32
40
|
"settings.stepDuration": "每步耗时",
|
|
33
41
|
"settings.stepDuration.hint": "紧跟每一行的文字显示这一步的开始时刻与耗时(如 14:32 · 23s):过程组头是整组、展开后的工具调用与思考行是它自己那一段;正在跑的那一行每秒更新",
|
|
42
|
+
"settings.sessionInfo": "会话信息",
|
|
43
|
+
"settings.sessionInfo.hint": "在主对话区右上角悬浮展示当前会话的信息看板(如已注入的 Skill、触发方式与轮次),点击条目可打开 Skill 预览",
|
|
34
44
|
"settings.suggestModel": "建议用哪个模型",
|
|
35
45
|
"settings.suggestModel.hint": "留空则跟随当前会话的模型;建议选一个非推理的轻量模型,否则每条建议都要等它想完",
|
|
36
46
|
"settings.suggestModel.follow": "跟随当前会话",
|
|
@@ -65,6 +75,14 @@ window.__ModuleLoader__.load({
|
|
|
65
75
|
"suggest.loading": "Thinking of the next round…",
|
|
66
76
|
"suggest.dismiss": "Dismiss suggestions",
|
|
67
77
|
"suggest.failed": "Nothing was written into the composer (the host is busy, or the draft conflicted). Try again.",
|
|
78
|
+
"sessionInfo.title": "Session info",
|
|
79
|
+
"sessionInfo.collapse": "Collapse session info",
|
|
80
|
+
"sessionInfo.expand": "Expand session info",
|
|
81
|
+
"sessionInfo.skills.title": "Active skills",
|
|
82
|
+
"sessionInfo.skills.short": "Skill",
|
|
83
|
+
"sessionInfo.skills.empty": "No active skills",
|
|
84
|
+
"sessionInfo.trigger.user": "User",
|
|
85
|
+
"sessionInfo.trigger.agent": "Agent",
|
|
68
86
|
"settings.title": "UI enhancements",
|
|
69
87
|
"settings.description": "Switch each interface enhancement this plugin adds. Turning one off restores the native DSH look.",
|
|
70
88
|
"settings.findBar": "Find in conversation",
|
|
@@ -77,6 +95,8 @@ window.__ModuleLoader__.load({
|
|
|
77
95
|
"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
96
|
"settings.stepDuration": "Step durations",
|
|
79
97
|
"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",
|
|
98
|
+
"settings.sessionInfo": "Session info",
|
|
99
|
+
"settings.sessionInfo.hint": "Shows a floating Session Info inspector in the top-right corner of the conversation view (active skills, trigger source, and turn); click an item to open its skill preview",
|
|
80
100
|
"settings.suggestModel": "Model for suggestions",
|
|
81
101
|
"settings.suggestModel.hint": "Empty follows the current session model. Prefer a lightweight non-reasoning model, or every suggestion waits for it to finish thinking",
|
|
82
102
|
"settings.suggestModel.follow": "Follow the current session",
|
|
@@ -361,14 +381,16 @@ window.__ModuleLoader__.load({
|
|
|
361
381
|
turnPrefix: "data-desktop-enhance-off-turn-prefix",
|
|
362
382
|
compactionRow: "data-desktop-enhance-off-compaction-row",
|
|
363
383
|
suggest: "data-desktop-enhance-off-suggest",
|
|
364
|
-
stepDuration: "data-desktop-enhance-off-step-duration"
|
|
384
|
+
stepDuration: "data-desktop-enhance-off-step-duration",
|
|
385
|
+
sessionInfo: "data-desktop-enhance-off-session-info"
|
|
365
386
|
};
|
|
366
387
|
const FIELDS = [
|
|
367
388
|
"findBar",
|
|
368
389
|
"turnPrefix",
|
|
369
390
|
"compactionRow",
|
|
370
391
|
"suggest",
|
|
371
|
-
"stepDuration"
|
|
392
|
+
"stepDuration",
|
|
393
|
+
"sessionInfo"
|
|
372
394
|
];
|
|
373
395
|
const ALL_FIELDS = [...FIELDS, ...TEXT_FIELDS];
|
|
374
396
|
function flagOn(value, field) {
|
|
@@ -434,6 +456,7 @@ window.__ModuleLoader__.load({
|
|
|
434
456
|
//#region src/shared/route.ts
|
|
435
457
|
const SUGGEST_ROUTE = "/api/desktop-enhance/suggest";
|
|
436
458
|
const SUGGEST_MODELS_ROUTE = "/api/desktop-enhance/suggest-models";
|
|
459
|
+
const SESSION_INFO_ROUTE = "/api/desktop-enhance/session-info";
|
|
437
460
|
//#endregion
|
|
438
461
|
//#region src/client/settings/catalog.ts
|
|
439
462
|
function parseModelCatalog(body) {
|
|
@@ -1939,8 +1962,466 @@ window.__ModuleLoader__.load({
|
|
|
1939
1962
|
]);
|
|
1940
1963
|
}
|
|
1941
1964
|
//#endregion
|
|
1965
|
+
//#region src/shared/session-info.ts
|
|
1966
|
+
const SKILL_CONTENT_RE = /^\s*<skill_content\s+name="([^"]+)">/;
|
|
1967
|
+
function asRecord(value) {
|
|
1968
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
1969
|
+
}
|
|
1970
|
+
function nonEmptyString(value) {
|
|
1971
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
1972
|
+
}
|
|
1973
|
+
function nonNegativeInt(value) {
|
|
1974
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
1975
|
+
}
|
|
1976
|
+
function positiveInt(value) {
|
|
1977
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : void 0;
|
|
1978
|
+
}
|
|
1979
|
+
function firstTextOf(content) {
|
|
1980
|
+
if (!Array.isArray(content)) return "";
|
|
1981
|
+
for (const item of content) {
|
|
1982
|
+
const block = asRecord(item);
|
|
1983
|
+
if (block?.type === "text") return typeof block.text === "string" ? block.text : "";
|
|
1984
|
+
}
|
|
1985
|
+
return "";
|
|
1986
|
+
}
|
|
1987
|
+
function toolSkillName(message) {
|
|
1988
|
+
if (message === null || message.isError === true) return void 0;
|
|
1989
|
+
return SKILL_CONTENT_RE.exec(firstTextOf(message.content))?.[1];
|
|
1990
|
+
}
|
|
1991
|
+
function invokedSkillName(type, data) {
|
|
1992
|
+
const source = asRecord((type === "developer/message" ? asRecord(data?.message) : data)?.source);
|
|
1993
|
+
if (source?.kind !== "skill-invocation") return void 0;
|
|
1994
|
+
return nonEmptyString(source.name);
|
|
1995
|
+
}
|
|
1996
|
+
function replaceRangeOf(surfaceOp) {
|
|
1997
|
+
const op = asRecord(surfaceOp);
|
|
1998
|
+
if (op?.op !== "replace") return null;
|
|
1999
|
+
const startSeq = nonNegativeInt(op.startSeq);
|
|
2000
|
+
const endSeq = nonNegativeInt(op.endSeq);
|
|
2001
|
+
if (startSeq === void 0 || endSeq === void 0 || endSeq < startSeq) return null;
|
|
2002
|
+
return {
|
|
2003
|
+
startSeq,
|
|
2004
|
+
endSeq
|
|
2005
|
+
};
|
|
2006
|
+
}
|
|
2007
|
+
function isSeqShadowed(seq, replacedRanges, shadowedSet) {
|
|
2008
|
+
if (shadowedSet.has(seq)) return true;
|
|
2009
|
+
for (const range of replacedRanges) if (seq >= range.startSeq && seq <= range.endSeq) return true;
|
|
2010
|
+
return false;
|
|
2011
|
+
}
|
|
2012
|
+
function deduplicateSkills(nodes) {
|
|
2013
|
+
const byName = new Map();
|
|
2014
|
+
for (const node of nodes) byName.set(node.name, node);
|
|
2015
|
+
return [...byName.values()];
|
|
2016
|
+
}
|
|
2017
|
+
function projectSkills(events) {
|
|
2018
|
+
let windowStartSeq = null;
|
|
2019
|
+
let currentTurn;
|
|
2020
|
+
const rawNodes = [];
|
|
2021
|
+
const replacedRanges = [];
|
|
2022
|
+
const shadowedSeqs = [];
|
|
2023
|
+
const shadowedSet = new Set();
|
|
2024
|
+
for (const raw of events) {
|
|
2025
|
+
const ev = asRecord(raw);
|
|
2026
|
+
if (ev === null) continue;
|
|
2027
|
+
const seq = nonNegativeInt(ev.seq);
|
|
2028
|
+
if (seq !== void 0 && (windowStartSeq === null || seq < windowStartSeq)) windowStartSeq = seq;
|
|
2029
|
+
const range = replaceRangeOf(ev.surfaceOp);
|
|
2030
|
+
if (range !== null) replacedRanges.push(range);
|
|
2031
|
+
const data = asRecord(ev.data);
|
|
2032
|
+
const turnInEvent = positiveInt(data?.turn);
|
|
2033
|
+
if (range === null && turnInEvent !== void 0) currentTurn = turnInEvent;
|
|
2034
|
+
const effectiveTurn = turnInEvent ?? currentTurn;
|
|
2035
|
+
const type = nonEmptyString(ev.type);
|
|
2036
|
+
if (type === "compaction/summary" || type === "compaction/prune") {
|
|
2037
|
+
const list = data?.shadowedSeqs;
|
|
2038
|
+
if (Array.isArray(list)) for (const item of list) {
|
|
2039
|
+
const s = nonNegativeInt(item);
|
|
2040
|
+
if (s !== void 0 && !shadowedSet.has(s)) {
|
|
2041
|
+
shadowedSet.add(s);
|
|
2042
|
+
shadowedSeqs.push(s);
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
continue;
|
|
2046
|
+
}
|
|
2047
|
+
if (seq === void 0) continue;
|
|
2048
|
+
if (type === "user/message" || type === "developer/message") {
|
|
2049
|
+
const name = invokedSkillName(type, data);
|
|
2050
|
+
if (name !== void 0) rawNodes.push({
|
|
2051
|
+
name,
|
|
2052
|
+
trigger: "user",
|
|
2053
|
+
seq,
|
|
2054
|
+
...effectiveTurn === void 0 ? {} : { turn: effectiveTurn }
|
|
2055
|
+
});
|
|
2056
|
+
continue;
|
|
2057
|
+
}
|
|
2058
|
+
if (type === "tool/result") {
|
|
2059
|
+
const name = toolSkillName(asRecord(data?.message));
|
|
2060
|
+
if (name !== void 0) rawNodes.push({
|
|
2061
|
+
name,
|
|
2062
|
+
trigger: "agent",
|
|
2063
|
+
seq,
|
|
2064
|
+
...effectiveTurn === void 0 ? {} : { turn: effectiveTurn }
|
|
2065
|
+
});
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
const surviving = rawNodes.filter((node) => !isSeqShadowed(node.seq, replacedRanges, shadowedSet));
|
|
2069
|
+
return {
|
|
2070
|
+
skills: deduplicateSkills(surviving),
|
|
2071
|
+
nodes: surviving,
|
|
2072
|
+
windowStartSeq,
|
|
2073
|
+
replacedRanges,
|
|
2074
|
+
shadowedSeqs
|
|
2075
|
+
};
|
|
2076
|
+
}
|
|
2077
|
+
function mergeSkillProjections(host, client) {
|
|
2078
|
+
if (host === null) return client.skills;
|
|
2079
|
+
if (client.windowStartSeq === null) return host.skills;
|
|
2080
|
+
if (client.windowStartSeq === 0) return client.skills;
|
|
2081
|
+
const windowStart = client.windowStartSeq;
|
|
2082
|
+
const clientShadowed = new Set(client.shadowedSeqs);
|
|
2083
|
+
const hostNodes = host.nodes ?? host.skills;
|
|
2084
|
+
const clientNodes = client.nodes ?? client.skills;
|
|
2085
|
+
return deduplicateSkills([...hostNodes.filter((skill) => skill.seq < windowStart && !isSeqShadowed(skill.seq, client.replacedRanges, clientShadowed)), ...clientNodes]);
|
|
2086
|
+
}
|
|
2087
|
+
function parseSkillArray(list) {
|
|
2088
|
+
const out = [];
|
|
2089
|
+
for (const item of list) {
|
|
2090
|
+
const row = asRecord(item);
|
|
2091
|
+
if (row === null) continue;
|
|
2092
|
+
const name = nonEmptyString(row.name);
|
|
2093
|
+
const trigger = row.trigger === "user" || row.trigger === "agent" ? row.trigger : void 0;
|
|
2094
|
+
const seq = nonNegativeInt(row.seq);
|
|
2095
|
+
const turn = positiveInt(row.turn);
|
|
2096
|
+
if (name !== void 0 && trigger !== void 0 && seq !== void 0) out.push({
|
|
2097
|
+
name,
|
|
2098
|
+
trigger,
|
|
2099
|
+
seq,
|
|
2100
|
+
...turn === void 0 ? {} : { turn }
|
|
2101
|
+
});
|
|
2102
|
+
}
|
|
2103
|
+
return out;
|
|
2104
|
+
}
|
|
2105
|
+
function normalizeSkillProjection(raw) {
|
|
2106
|
+
const rec = asRecord(raw);
|
|
2107
|
+
if (rec === null || !Array.isArray(rec.skills)) return null;
|
|
2108
|
+
const skills = parseSkillArray(rec.skills);
|
|
2109
|
+
const nodes = Array.isArray(rec.nodes) ? parseSkillArray(rec.nodes) : skills;
|
|
2110
|
+
const windowStartSeq = nonNegativeInt(rec.windowStartSeq) ?? null;
|
|
2111
|
+
const replacedRanges = [];
|
|
2112
|
+
if (Array.isArray(rec.replacedRanges)) for (const item of rec.replacedRanges) {
|
|
2113
|
+
const r = asRecord(item);
|
|
2114
|
+
const startSeq = nonNegativeInt(r?.startSeq);
|
|
2115
|
+
const endSeq = nonNegativeInt(r?.endSeq);
|
|
2116
|
+
if (startSeq !== void 0 && endSeq !== void 0 && endSeq >= startSeq) replacedRanges.push({
|
|
2117
|
+
startSeq,
|
|
2118
|
+
endSeq
|
|
2119
|
+
});
|
|
2120
|
+
}
|
|
2121
|
+
const shadowedSeqs = [];
|
|
2122
|
+
if (Array.isArray(rec.shadowedSeqs)) for (const item of rec.shadowedSeqs) {
|
|
2123
|
+
const s = nonNegativeInt(item);
|
|
2124
|
+
if (s !== void 0) shadowedSeqs.push(s);
|
|
2125
|
+
}
|
|
2126
|
+
return {
|
|
2127
|
+
skills,
|
|
2128
|
+
nodes,
|
|
2129
|
+
windowStartSeq,
|
|
2130
|
+
replacedRanges,
|
|
2131
|
+
shadowedSeqs
|
|
2132
|
+
};
|
|
2133
|
+
}
|
|
2134
|
+
function buildSessionInfoSections(skills, t) {
|
|
2135
|
+
return [{
|
|
2136
|
+
id: "skills",
|
|
2137
|
+
title: t("sessionInfo.skills.title"),
|
|
2138
|
+
shortLabel: t("sessionInfo.skills.short"),
|
|
2139
|
+
emptyText: t("sessionInfo.skills.empty"),
|
|
2140
|
+
items: skills.map((skill) => ({
|
|
2141
|
+
name: skill.name,
|
|
2142
|
+
badge: skill.trigger === "user" ? t("sessionInfo.trigger.user") : t("sessionInfo.trigger.agent"),
|
|
2143
|
+
...skill.turn === void 0 ? {} : { turnLabel: `#${String(skill.turn)}` }
|
|
2144
|
+
}))
|
|
2145
|
+
}];
|
|
2146
|
+
}
|
|
2147
|
+
//#endregion
|
|
2148
|
+
//#region src/client/session-info/panel.ts
|
|
2149
|
+
const SESSION_INFO_ATTR = "data-desktop-enhance-session-info";
|
|
2150
|
+
const SESSION_INFO_URL = SESSION_INFO_ROUTE;
|
|
2151
|
+
function openSkillInHost(ctx, sessionId, name) {
|
|
2152
|
+
if (sessionId === "" || name === "") return false;
|
|
2153
|
+
const sessions = ctx.get("sessions");
|
|
2154
|
+
if (sessions === null || sessions === void 0 || typeof sessions.scope !== "function") return false;
|
|
2155
|
+
let scope;
|
|
2156
|
+
try {
|
|
2157
|
+
scope = sessions.scope(sessionId);
|
|
2158
|
+
} catch {
|
|
2159
|
+
return false;
|
|
2160
|
+
}
|
|
2161
|
+
if (scope === void 0 || scope === null) return false;
|
|
2162
|
+
const triggers = ctx.get("inputTriggers");
|
|
2163
|
+
if (triggers === null || triggers === void 0 || typeof triggers.sessionOf !== "function") return false;
|
|
2164
|
+
try {
|
|
2165
|
+
const controller = triggers.sessionOf(scope);
|
|
2166
|
+
if (controller === void 0 || typeof controller.openReference !== "function") return false;
|
|
2167
|
+
return Boolean(controller.openReference("skill", { ref: `/${name}` }));
|
|
2168
|
+
} catch {
|
|
2169
|
+
return false;
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
async function requestSessionInfo(fetchImpl, sessionId) {
|
|
2173
|
+
try {
|
|
2174
|
+
const response = await fetchImpl(SESSION_INFO_URL, {
|
|
2175
|
+
method: "POST",
|
|
2176
|
+
headers: { "content-type": "application/json" },
|
|
2177
|
+
body: JSON.stringify({ sessionId })
|
|
2178
|
+
});
|
|
2179
|
+
if (!response.ok) return null;
|
|
2180
|
+
return normalizeSkillProjection(await response.json());
|
|
2181
|
+
} catch {
|
|
2182
|
+
return null;
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
function findActiveChatConversation() {
|
|
2186
|
+
if (typeof globalThis.document?.querySelector !== "function") return null;
|
|
2187
|
+
const root = globalThis.document.querySelector("[data-conversation-session]");
|
|
2188
|
+
if (root === null || typeof root.querySelector !== "function") return null;
|
|
2189
|
+
const sessionId = root.getAttribute("data-conversation-session");
|
|
2190
|
+
if (sessionId === null || sessionId === "") return null;
|
|
2191
|
+
if (root.querySelector("[data-chat-flow]") === null) return null;
|
|
2192
|
+
return {
|
|
2193
|
+
root,
|
|
2194
|
+
sessionId
|
|
2195
|
+
};
|
|
2196
|
+
}
|
|
2197
|
+
function renderSignature(sections, minimized, collapsedSections) {
|
|
2198
|
+
return JSON.stringify({
|
|
2199
|
+
minimized,
|
|
2200
|
+
collapsed: [...collapsedSections].sort(),
|
|
2201
|
+
sections
|
|
2202
|
+
});
|
|
2203
|
+
}
|
|
2204
|
+
function installSessionInfo(ctx, isOn, getSessions, t, fetchImpl = globalThis.fetch) {
|
|
2205
|
+
let activeSessionId = null;
|
|
2206
|
+
let retained = null;
|
|
2207
|
+
let unsubscribeSource = null;
|
|
2208
|
+
let hostProjection = null;
|
|
2209
|
+
let fetchToken = 0;
|
|
2210
|
+
let minimized = false;
|
|
2211
|
+
const collapsedSections = new Set();
|
|
2212
|
+
let mountedPanel = null;
|
|
2213
|
+
let lastSignature = "";
|
|
2214
|
+
function removePanel() {
|
|
2215
|
+
if (mountedPanel !== null) {
|
|
2216
|
+
mountedPanel.remove();
|
|
2217
|
+
mountedPanel = null;
|
|
2218
|
+
}
|
|
2219
|
+
lastSignature = "";
|
|
2220
|
+
}
|
|
2221
|
+
function detach() {
|
|
2222
|
+
fetchToken += 1;
|
|
2223
|
+
if (unsubscribeSource !== null) {
|
|
2224
|
+
unsubscribeSource();
|
|
2225
|
+
unsubscribeSource = null;
|
|
2226
|
+
}
|
|
2227
|
+
if (retained !== null) {
|
|
2228
|
+
retained.release();
|
|
2229
|
+
retained = null;
|
|
2230
|
+
}
|
|
2231
|
+
activeSessionId = null;
|
|
2232
|
+
hostProjection = null;
|
|
2233
|
+
removePanel();
|
|
2234
|
+
}
|
|
2235
|
+
function currentClientProjection() {
|
|
2236
|
+
return projectSkills(eventsOf(retained?.binding.eventSource.getSnapshot().entries ?? []));
|
|
2237
|
+
}
|
|
2238
|
+
function paint(root, sessionId) {
|
|
2239
|
+
const clientProjection = currentClientProjection();
|
|
2240
|
+
const sections = buildSessionInfoSections(mergeSkillProjections(hostProjection, clientProjection), t);
|
|
2241
|
+
const totalItems = sections.reduce((sum, sec) => sum + sec.items.length, 0);
|
|
2242
|
+
const sig = renderSignature(sections, minimized, collapsedSections);
|
|
2243
|
+
let panel = root.querySelector(`[${SESSION_INFO_ATTR}]`);
|
|
2244
|
+
if (panel === null) {
|
|
2245
|
+
panel = globalThis.document.createElement("aside");
|
|
2246
|
+
panel.setAttribute(SESSION_INFO_ATTR, "");
|
|
2247
|
+
root.appendChild(panel);
|
|
2248
|
+
mountedPanel = panel;
|
|
2249
|
+
lastSignature = "";
|
|
2250
|
+
} else mountedPanel = panel;
|
|
2251
|
+
if (sig === lastSignature) return;
|
|
2252
|
+
lastSignature = sig;
|
|
2253
|
+
panel.setAttribute("data-minimized", minimized ? "true" : "false");
|
|
2254
|
+
panel.setAttribute("data-empty", totalItems === 0 ? "true" : "false");
|
|
2255
|
+
const header = globalThis.document.createElement("button");
|
|
2256
|
+
header.setAttribute("type", "button");
|
|
2257
|
+
header.setAttribute("data-session-info-header", "");
|
|
2258
|
+
header.setAttribute("aria-expanded", minimized ? "false" : "true");
|
|
2259
|
+
header.setAttribute("aria-label", minimized ? t("sessionInfo.expand") : t("sessionInfo.collapse"));
|
|
2260
|
+
const titleWrap = globalThis.document.createElement("span");
|
|
2261
|
+
titleWrap.setAttribute("data-session-info-title", "");
|
|
2262
|
+
const dot = globalThis.document.createElement("span");
|
|
2263
|
+
dot.setAttribute("data-session-info-dot", totalItems === 0 ? "idle" : "active");
|
|
2264
|
+
titleWrap.appendChild(dot);
|
|
2265
|
+
const titleText = globalThis.document.createElement("span");
|
|
2266
|
+
if (minimized) {
|
|
2267
|
+
const summary = sections.map((sec) => `${sec.shortLabel} ${String(sec.items.length)}`).join(" · ");
|
|
2268
|
+
titleText.textContent = `${t("sessionInfo.title")} · ${summary}`;
|
|
2269
|
+
} else titleText.textContent = t("sessionInfo.title");
|
|
2270
|
+
titleWrap.appendChild(titleText);
|
|
2271
|
+
header.appendChild(titleWrap);
|
|
2272
|
+
const toggleIcon = globalThis.document.createElement("span");
|
|
2273
|
+
toggleIcon.setAttribute("data-session-info-chevron", "");
|
|
2274
|
+
toggleIcon.textContent = minimized ? "▾" : "−";
|
|
2275
|
+
header.appendChild(toggleIcon);
|
|
2276
|
+
header.addEventListener("click", () => {
|
|
2277
|
+
minimized = !minimized;
|
|
2278
|
+
paint(root, sessionId);
|
|
2279
|
+
});
|
|
2280
|
+
const children = [header];
|
|
2281
|
+
if (!minimized) for (const sec of sections) {
|
|
2282
|
+
const secCollapsed = collapsedSections.has(sec.id);
|
|
2283
|
+
const secEl = globalThis.document.createElement("section");
|
|
2284
|
+
secEl.setAttribute("data-session-info-section", sec.id);
|
|
2285
|
+
secEl.setAttribute("data-collapsed", secCollapsed ? "true" : "false");
|
|
2286
|
+
const secHead = globalThis.document.createElement("button");
|
|
2287
|
+
secHead.setAttribute("type", "button");
|
|
2288
|
+
secHead.setAttribute("data-session-info-section-header", sec.id);
|
|
2289
|
+
secHead.setAttribute("aria-expanded", secCollapsed ? "false" : "true");
|
|
2290
|
+
const secHeadLeft = globalThis.document.createElement("span");
|
|
2291
|
+
secHeadLeft.setAttribute("data-session-info-section-label", "");
|
|
2292
|
+
const arrow = globalThis.document.createElement("span");
|
|
2293
|
+
arrow.setAttribute("data-session-info-arrow", "");
|
|
2294
|
+
arrow.textContent = secCollapsed ? "▸" : "▾";
|
|
2295
|
+
secHeadLeft.appendChild(arrow);
|
|
2296
|
+
const secTitle = globalThis.document.createElement("span");
|
|
2297
|
+
secTitle.textContent = sec.title;
|
|
2298
|
+
secHeadLeft.appendChild(secTitle);
|
|
2299
|
+
secHead.appendChild(secHeadLeft);
|
|
2300
|
+
const countBadge = globalThis.document.createElement("span");
|
|
2301
|
+
countBadge.setAttribute("data-session-info-count", "");
|
|
2302
|
+
countBadge.textContent = String(sec.items.length);
|
|
2303
|
+
secHead.appendChild(countBadge);
|
|
2304
|
+
secHead.addEventListener("click", () => {
|
|
2305
|
+
if (collapsedSections.has(sec.id)) collapsedSections.delete(sec.id);
|
|
2306
|
+
else collapsedSections.add(sec.id);
|
|
2307
|
+
paint(root, sessionId);
|
|
2308
|
+
});
|
|
2309
|
+
secEl.appendChild(secHead);
|
|
2310
|
+
if (!secCollapsed) {
|
|
2311
|
+
const body = globalThis.document.createElement("div");
|
|
2312
|
+
body.setAttribute("data-session-info-body", "");
|
|
2313
|
+
if (sec.items.length === 0) {
|
|
2314
|
+
const empty = globalThis.document.createElement("div");
|
|
2315
|
+
empty.setAttribute("data-session-info-empty", "");
|
|
2316
|
+
empty.textContent = sec.emptyText;
|
|
2317
|
+
body.appendChild(empty);
|
|
2318
|
+
} else for (const item of sec.items) {
|
|
2319
|
+
const row = globalThis.document.createElement("button");
|
|
2320
|
+
row.setAttribute("type", "button");
|
|
2321
|
+
row.setAttribute("data-session-info-item", item.name);
|
|
2322
|
+
const nameSpan = globalThis.document.createElement("span");
|
|
2323
|
+
nameSpan.setAttribute("data-session-info-item-name", "");
|
|
2324
|
+
nameSpan.textContent = item.name;
|
|
2325
|
+
row.appendChild(nameSpan);
|
|
2326
|
+
const metaSpan = globalThis.document.createElement("span");
|
|
2327
|
+
metaSpan.setAttribute("data-session-info-item-meta", "");
|
|
2328
|
+
const badgeSpan = globalThis.document.createElement("span");
|
|
2329
|
+
badgeSpan.setAttribute("data-session-info-item-badge", "");
|
|
2330
|
+
badgeSpan.textContent = item.badge;
|
|
2331
|
+
metaSpan.appendChild(badgeSpan);
|
|
2332
|
+
if (item.turnLabel !== void 0) {
|
|
2333
|
+
const turnSpan = globalThis.document.createElement("span");
|
|
2334
|
+
turnSpan.setAttribute("data-session-info-item-turn", "");
|
|
2335
|
+
turnSpan.textContent = item.turnLabel;
|
|
2336
|
+
metaSpan.appendChild(turnSpan);
|
|
2337
|
+
}
|
|
2338
|
+
row.appendChild(metaSpan);
|
|
2339
|
+
row.addEventListener("click", () => {
|
|
2340
|
+
openSkillInHost(ctx, sessionId, item.name);
|
|
2341
|
+
});
|
|
2342
|
+
body.appendChild(row);
|
|
2343
|
+
}
|
|
2344
|
+
secEl.appendChild(body);
|
|
2345
|
+
}
|
|
2346
|
+
children.push(secEl);
|
|
2347
|
+
}
|
|
2348
|
+
panel.replaceChildren(...children);
|
|
2349
|
+
}
|
|
2350
|
+
function triggerHostRefresh(sessionId, root) {
|
|
2351
|
+
const token = ++fetchToken;
|
|
2352
|
+
requestSessionInfo(fetchImpl, sessionId).then((result) => {
|
|
2353
|
+
if (token !== fetchToken || activeSessionId !== sessionId || result === null) return;
|
|
2354
|
+
hostProjection = result;
|
|
2355
|
+
const current = findActiveChatConversation();
|
|
2356
|
+
paint(current?.sessionId === sessionId ? current.root : root, sessionId);
|
|
2357
|
+
});
|
|
2358
|
+
}
|
|
2359
|
+
function attach(sessionId, root) {
|
|
2360
|
+
const service = getSessions();
|
|
2361
|
+
if (service === null || service === void 0 || typeof service.retain !== "function") return;
|
|
2362
|
+
let next;
|
|
2363
|
+
try {
|
|
2364
|
+
next = service.retain(sessionId, { source: NS });
|
|
2365
|
+
} catch {
|
|
2366
|
+
return;
|
|
2367
|
+
}
|
|
2368
|
+
activeSessionId = sessionId;
|
|
2369
|
+
retained = next;
|
|
2370
|
+
hostProjection = null;
|
|
2371
|
+
let fetchedForWindowStart = void 0;
|
|
2372
|
+
const maybeRequestHost = (targetRoot) => {
|
|
2373
|
+
const ws = currentClientProjection().windowStartSeq;
|
|
2374
|
+
if (ws !== 0 && ws !== fetchedForWindowStart) {
|
|
2375
|
+
fetchedForWindowStart = ws;
|
|
2376
|
+
triggerHostRefresh(sessionId, targetRoot);
|
|
2377
|
+
}
|
|
2378
|
+
};
|
|
2379
|
+
const source = next.binding.eventSource;
|
|
2380
|
+
paint(root, sessionId);
|
|
2381
|
+
maybeRequestHost(root);
|
|
2382
|
+
unsubscribeSource = source.subscribe(() => {
|
|
2383
|
+
const current = findActiveChatConversation();
|
|
2384
|
+
const targetRoot = current?.sessionId === sessionId ? current.root : root;
|
|
2385
|
+
paint(targetRoot, sessionId);
|
|
2386
|
+
maybeRequestHost(targetRoot);
|
|
2387
|
+
});
|
|
2388
|
+
}
|
|
2389
|
+
function sync() {
|
|
2390
|
+
if (!isOn()) {
|
|
2391
|
+
detach();
|
|
2392
|
+
return;
|
|
2393
|
+
}
|
|
2394
|
+
const found = findActiveChatConversation();
|
|
2395
|
+
if (found === null) {
|
|
2396
|
+
detach();
|
|
2397
|
+
return;
|
|
2398
|
+
}
|
|
2399
|
+
if (found.sessionId !== activeSessionId) {
|
|
2400
|
+
detach();
|
|
2401
|
+
attach(found.sessionId, found.root);
|
|
2402
|
+
return;
|
|
2403
|
+
}
|
|
2404
|
+
paint(found.root, found.sessionId);
|
|
2405
|
+
}
|
|
2406
|
+
ctx.effect(() => {
|
|
2407
|
+
const observer = new globalThis.MutationObserver(() => {
|
|
2408
|
+
sync();
|
|
2409
|
+
});
|
|
2410
|
+
observer.observe(globalThis.document.documentElement, {
|
|
2411
|
+
childList: true,
|
|
2412
|
+
subtree: true
|
|
2413
|
+
});
|
|
2414
|
+
return () => {
|
|
2415
|
+
observer.disconnect();
|
|
2416
|
+
detach();
|
|
2417
|
+
};
|
|
2418
|
+
}, "desktop-enhance: session-info observer");
|
|
2419
|
+
sync();
|
|
2420
|
+
return { refresh: sync };
|
|
2421
|
+
}
|
|
2422
|
+
//#endregion
|
|
1942
2423
|
//#region \0dsh-desktop-enhance-css:/Users/lijiechengbj/projects/AI-agents/dsh-desktop-enhance/src/client/styles/enhance.css.mjs
|
|
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:root:not([data-desktop-enhance-off-compaction-row])\n [hidden=\"until-found\"]:has([data-chat-flow-kind=\"manual-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:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"manual-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\"]):not([data-chat-flow-kind=\"manual-compaction\"]),\n:root:not([data-desktop-enhance-off-compaction-row])\n [hidden=\"until-found\"]:has([data-chat-flow-kind=\"manual-compaction\"])\n [data-turn-process-member=\"true\"]:not([data-chat-flow-kind=\"compaction\"]):not([data-chat-flow-kind=\"manual-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:root:not([data-desktop-enhance-off-compaction-row])\n [data-step-process=\"true\"][hidden=\"until-found\"]:has([data-chat-flow-kind=\"manual-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";
|
|
2424
|
+
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:root:not([data-desktop-enhance-off-compaction-row])\n [hidden=\"until-found\"]:has([data-chat-flow-kind=\"manual-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:root:not([data-desktop-enhance-off-compaction-row])\n [data-chat-flow-kind=\"manual-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\"]):not([data-chat-flow-kind=\"manual-compaction\"]),\n:root:not([data-desktop-enhance-off-compaction-row])\n [hidden=\"until-found\"]:has([data-chat-flow-kind=\"manual-compaction\"])\n [data-turn-process-member=\"true\"]:not([data-chat-flow-kind=\"compaction\"]):not([data-chat-flow-kind=\"manual-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:root:not([data-desktop-enhance-off-compaction-row])\n [data-step-process=\"true\"][hidden=\"until-found\"]:has([data-chat-flow-kind=\"manual-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\n\n:root[data-desktop-enhance-off-session-info] [data-desktop-enhance-session-info] {\n display: none !important;\n}\n:root:not([data-desktop-enhance-off-session-info]) [data-desktop-enhance-session-info] {\n position: absolute;\n top: 12px;\n right: 36px;\n z-index: 10;\n width: 244px;\n box-sizing: border-box;\n border-radius: var(--dsw-radius-lg);\n border: 1px solid var(--dsw-alias-border-l2);\n background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 90%, transparent);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n box-shadow: var(--dsw-elevation-panel);\n color: var(--dsw-alias-label-primary);\n overflow: hidden;\n}\n:root:not([data-desktop-enhance-off-session-info])\n [data-desktop-enhance-session-info][data-minimized=\"true\"] {\n width: auto;\n border-radius: 999px;\n}\n[data-desktop-enhance-session-info] [data-session-info-header] {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 6px 10px;\n border: none;\n border-bottom: 0.5px solid var(--dsw-alias-border-l2);\n background: color-mix(in srgb, var(--dsw-alias-bg-module-platform) 60%, transparent);\n color: var(--dsw-alias-label-secondary);\n font: var(--dsw-font-xxs-strong-12, 600 12px/18px sans-serif);\n cursor: pointer;\n user-select: none;\n}\n[data-desktop-enhance-session-info][data-minimized=\"true\"] [data-session-info-header] {\n border-bottom: none;\n background: transparent;\n padding: 5px 11px;\n}\n[data-desktop-enhance-session-info] [data-session-info-header]:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n[data-desktop-enhance-session-info] [data-session-info-title] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n}\n[data-desktop-enhance-session-info] [data-session-info-dot] {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n flex: none;\n background: var(--dsw-alias-state-business-primary);\n box-shadow: 0 0 0 2.5px var(--dsw-alias-state-business-tertiary);\n}\n[data-desktop-enhance-session-info] [data-session-info-dot=\"idle\"] {\n background: var(--dsw-alias-label-caption);\n box-shadow: none;\n}\n[data-desktop-enhance-session-info] [data-session-info-chevron] {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n line-height: 1;\n}\n[data-desktop-enhance-session-info] [data-session-info-section] {\n border-bottom: 0.5px solid var(--dsw-alias-border-l2);\n}\n[data-desktop-enhance-session-info] [data-session-info-section]:last-child {\n border-bottom: none;\n}\n[data-desktop-enhance-session-info] [data-session-info-section-header] {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 6px 10px;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font: var(--dsw-font-xxs-strong-12, 600 12px/18px sans-serif);\n cursor: pointer;\n user-select: none;\n}\n[data-desktop-enhance-session-info] [data-session-info-section-header]:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n[data-desktop-enhance-session-info] [data-session-info-section-label] {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n min-width: 0;\n}\n[data-desktop-enhance-session-info] [data-session-info-arrow] {\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n}\n[data-desktop-enhance-session-info] [data-session-info-count] {\n font-family: var(--dsw-font-family-mono, ui-monospace, SFMono-Regular, Menlo, monospace);\n font-size: 11px;\n font-weight: 600;\n padding: 0 5px;\n line-height: 16px;\n border-radius: 999px;\n background: var(--dsw-alias-state-business-tertiary);\n color: var(--dsw-alias-label-primary-bluish);\n}\n[data-desktop-enhance-session-info][data-empty=\"true\"] [data-session-info-count] {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n color: var(--dsw-alias-label-tertiary);\n}\n[data-desktop-enhance-session-info] [data-session-info-body] {\n padding: 2px 6px 6px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n max-height: 184px;\n overflow-y: auto;\n}\n[data-desktop-enhance-session-info] [data-session-info-empty] {\n padding: 4px 6px;\n color: var(--dsw-alias-label-tertiary);\n font: var(--dsw-font-xxs-12);\n}\n[data-desktop-enhance-session-info] [data-session-info-item] {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 5px 8px;\n border: none;\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n text-align: left;\n}\n[data-desktop-enhance-session-info] [data-session-info-item]:hover {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n}\n[data-desktop-enhance-session-info] [data-session-info-item-name] {\n font-family: var(--dsw-font-family-mono, ui-monospace, SFMono-Regular, Menlo, monospace);\n font-size: 12px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n[data-desktop-enhance-session-info] [data-session-info-item-meta] {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n flex: none;\n}\n[data-desktop-enhance-session-info] [data-session-info-item-badge] {\n font-size: 10.5px;\n color: var(--dsw-alias-label-tertiary);\n}\n[data-desktop-enhance-session-info] [data-session-info-item-turn] {\n font-family: var(--dsw-font-family-mono, ui-monospace, SFMono-Regular, Menlo, monospace);\n font-size: 11px;\n padding: 0 5px;\n line-height: 16px;\n border-radius: var(--dsw-radius-xs);\n background: var(--dsw-alias-interactive-bg-hover-solid);\n color: var(--dsw-alias-label-secondary);\n}\n";
|
|
1944
2425
|
//#endregion
|
|
1945
2426
|
//#region src/client/index.tsx
|
|
1946
2427
|
const inject = [
|
|
@@ -2014,6 +2495,7 @@ window.__ModuleLoader__.load({
|
|
|
2014
2495
|
});
|
|
2015
2496
|
installTurnPrefix(ctx);
|
|
2016
2497
|
const timings = installTimings(ctx, () => flagOn(settings.get().value, "stepDuration"), () => ctx.get("sessions"));
|
|
2498
|
+
const sessionInfo = installSessionInfo(ctx, () => flagOn(settings.get().value, "sessionInfo"), () => ctx.get("sessions"), t);
|
|
2017
2499
|
const suggestStore = createSuggestStore();
|
|
2018
2500
|
const suggestWatcher = createSuggestWatcher(() => ctx.get("sessions"), suggestStore, {
|
|
2019
2501
|
fetchImpl: globalThis.fetch,
|
|
@@ -2024,6 +2506,7 @@ window.__ModuleLoader__.load({
|
|
|
2024
2506
|
const off = settings.subscribe(() => {
|
|
2025
2507
|
suggestWatcher.refresh();
|
|
2026
2508
|
timings.refresh();
|
|
2509
|
+
sessionInfo.refresh();
|
|
2027
2510
|
});
|
|
2028
2511
|
return () => {
|
|
2029
2512
|
off();
|
|
@@ -2169,7 +2652,16 @@ window.__ModuleLoader__.load({
|
|
|
2169
2652
|
anyRunning,
|
|
2170
2653
|
installTimings,
|
|
2171
2654
|
DURATION_ATTR,
|
|
2172
|
-
titleOf
|
|
2655
|
+
titleOf,
|
|
2656
|
+
projectSkills,
|
|
2657
|
+
mergeSkillProjections,
|
|
2658
|
+
normalizeSkillProjection,
|
|
2659
|
+
buildSessionInfoSections,
|
|
2660
|
+
SESSION_INFO_ATTR,
|
|
2661
|
+
SESSION_INFO_URL,
|
|
2662
|
+
requestSessionInfo,
|
|
2663
|
+
openSkillInHost,
|
|
2664
|
+
installSessionInfo
|
|
2173
2665
|
};
|
|
2174
2666
|
exports.apply = apply;
|
|
2175
2667
|
exports.inject = inject;
|
package/lib/index.d.ts
CHANGED
|
@@ -90,6 +90,10 @@ declare function listEfforts(ctx: HostContext, provider: string, model: string):
|
|
|
90
90
|
}>;
|
|
91
91
|
declare function registerSuggestRoute(ctx: HostContext): () => void;
|
|
92
92
|
//#endregion
|
|
93
|
+
//#region src/session-info/host.d.ts
|
|
94
|
+
declare function handleSessionInfo(ctx: HostContext, request: Request): Promise<Response>;
|
|
95
|
+
declare function registerSessionInfoRoute(ctx: HostContext): () => void;
|
|
96
|
+
//#endregion
|
|
93
97
|
//#region src/index.d.ts
|
|
94
98
|
export declare const Config: Schema<Schemastery.ObjectS<NoInfer<{
|
|
95
99
|
findBar: Schema<boolean, boolean, "volatile-defined">;
|
|
@@ -97,6 +101,7 @@ export declare const Config: Schema<Schemastery.ObjectS<NoInfer<{
|
|
|
97
101
|
compactionRow: Schema<boolean, boolean, "volatile-defined">;
|
|
98
102
|
suggest: Schema<boolean, boolean, "volatile-defined">;
|
|
99
103
|
stepDuration: Schema<boolean, boolean, "volatile-defined">;
|
|
104
|
+
sessionInfo: Schema<boolean, boolean, "volatile-defined">;
|
|
100
105
|
suggestModel: Schema<string, string, "volatile-defined">;
|
|
101
106
|
suggestReasoning: Schema<string, string, "volatile-defined">;
|
|
102
107
|
suggestPrompt: Schema<string, string, "volatile-defined">;
|
|
@@ -106,6 +111,7 @@ export declare const Config: Schema<Schemastery.ObjectS<NoInfer<{
|
|
|
106
111
|
compactionRow: Schema<boolean, boolean, "volatile-defined">;
|
|
107
112
|
suggest: Schema<boolean, boolean, "volatile-defined">;
|
|
108
113
|
stepDuration: Schema<boolean, boolean, "volatile-defined">;
|
|
114
|
+
sessionInfo: Schema<boolean, boolean, "volatile-defined">;
|
|
109
115
|
suggestModel: Schema<string, string, "volatile-defined">;
|
|
110
116
|
suggestReasoning: Schema<string, string, "volatile-defined">;
|
|
111
117
|
suggestPrompt: Schema<string, string, "volatile-defined">;
|
|
@@ -115,6 +121,7 @@ export declare const __test: {
|
|
|
115
121
|
SUGGEST_PATH: string;
|
|
116
122
|
SUGGEST_MODELS_PATH: string;
|
|
117
123
|
SUGGEST_EFFORTS_PATH: string;
|
|
124
|
+
SESSION_INFO_PATH: string;
|
|
118
125
|
MODEL_TIMEOUT_MS: number;
|
|
119
126
|
MAX_OUTPUT_TOKENS: number;
|
|
120
127
|
buildPrompt: typeof buildPrompt;
|
|
@@ -122,7 +129,9 @@ export declare const __test: {
|
|
|
122
129
|
collectText: typeof collectText;
|
|
123
130
|
knownNamesOf: typeof knownNamesOf;
|
|
124
131
|
handleSuggest: typeof handleSuggest;
|
|
132
|
+
handleSessionInfo: typeof handleSessionInfo;
|
|
125
133
|
registerSuggestRoute: typeof registerSuggestRoute;
|
|
134
|
+
registerSessionInfoRoute: typeof registerSessionInfoRoute;
|
|
126
135
|
routeOf: typeof routeOf;
|
|
127
136
|
quietEffortFor: typeof quietEffortFor;
|
|
128
137
|
listModels: typeof listModels;
|
package/lib/index.js
CHANGED
|
@@ -93,6 +93,7 @@ function splitRoute(model) {
|
|
|
93
93
|
const SUGGEST_ROUTE = "/api/desktop-enhance/suggest";
|
|
94
94
|
const SUGGEST_MODELS_ROUTE = "/api/desktop-enhance/suggest-models";
|
|
95
95
|
const SUGGEST_EFFORTS_ROUTE = "/api/desktop-enhance/suggest-efforts";
|
|
96
|
+
const SESSION_INFO_ROUTE = "/api/desktop-enhance/session-info";
|
|
96
97
|
//#endregion
|
|
97
98
|
//#region src/suggest/host.ts
|
|
98
99
|
const SUGGEST_PATH = SUGGEST_ROUTE;
|
|
@@ -156,7 +157,7 @@ function knownNamesOf(messages) {
|
|
|
156
157
|
return found ? names : null;
|
|
157
158
|
}
|
|
158
159
|
async function handleSuggest(ctx, request, timeoutMs = MODEL_TIMEOUT_MS) {
|
|
159
|
-
const empty = () => json({ items: [] });
|
|
160
|
+
const empty = () => json$1({ items: [] });
|
|
160
161
|
let sessionId;
|
|
161
162
|
let preference = FOLLOW_SESSION;
|
|
162
163
|
try {
|
|
@@ -168,9 +169,9 @@ async function handleSuggest(ctx, request, timeoutMs = MODEL_TIMEOUT_MS) {
|
|
|
168
169
|
prompt: typeof body.prompt === "string" ? body.prompt : ""
|
|
169
170
|
};
|
|
170
171
|
} catch {
|
|
171
|
-
return json({ items: [] }, 400);
|
|
172
|
+
return json$1({ items: [] }, 400);
|
|
172
173
|
}
|
|
173
|
-
if (typeof sessionId !== "string" || sessionId === "") return json({ items: [] }, 400);
|
|
174
|
+
if (typeof sessionId !== "string" || sessionId === "") return json$1({ items: [] }, 400);
|
|
174
175
|
const sessions = ctx.get("sessions");
|
|
175
176
|
const llm = ctx.get("llm");
|
|
176
177
|
if (sessions === null || sessions === void 0 || llm === null || llm === void 0) return empty();
|
|
@@ -229,7 +230,7 @@ async function handleSuggest(ctx, request, timeoutMs = MODEL_TIMEOUT_MS) {
|
|
|
229
230
|
}
|
|
230
231
|
function withDiag(ctx, body, record) {
|
|
231
232
|
logDiag(ctx, record);
|
|
232
|
-
return json({
|
|
233
|
+
return json$1({
|
|
233
234
|
...body,
|
|
234
235
|
diag: record
|
|
235
236
|
});
|
|
@@ -301,7 +302,7 @@ async function listEfforts(ctx, provider, model) {
|
|
|
301
302
|
};
|
|
302
303
|
}
|
|
303
304
|
}
|
|
304
|
-
function json(body, status = 200) {
|
|
305
|
+
function json$1(body, status = 200) {
|
|
305
306
|
return new Response(JSON.stringify(body), {
|
|
306
307
|
status,
|
|
307
308
|
headers: { "content-type": "application/json" }
|
|
@@ -322,7 +323,7 @@ function registerSuggestRoute(ctx) {
|
|
|
322
323
|
path: SUGGEST_MODELS_PATH,
|
|
323
324
|
methods: ["GET"],
|
|
324
325
|
requestBody: "buffered",
|
|
325
|
-
fetch: async () => json(await listModels(ctx))
|
|
326
|
+
fetch: async () => json$1(await listModels(ctx))
|
|
326
327
|
}));
|
|
327
328
|
disposers.push(registry.register({
|
|
328
329
|
path: SUGGEST_EFFORTS_PATH,
|
|
@@ -330,11 +331,11 @@ function registerSuggestRoute(ctx) {
|
|
|
330
331
|
requestBody: "buffered",
|
|
331
332
|
fetch: async (request) => {
|
|
332
333
|
const route = splitRoute(new URL(request.url).searchParams.get("model") ?? "");
|
|
333
|
-
if (route === null) return json({
|
|
334
|
+
if (route === null) return json$1({
|
|
334
335
|
efforts: [],
|
|
335
336
|
defaultEffort: null
|
|
336
337
|
});
|
|
337
|
-
return json(await listEfforts(ctx, route.provider, route.model));
|
|
338
|
+
return json$1(await listEfforts(ctx, route.provider, route.model));
|
|
338
339
|
}
|
|
339
340
|
}));
|
|
340
341
|
} catch (error) {
|
|
@@ -345,6 +346,195 @@ function registerSuggestRoute(ctx) {
|
|
|
345
346
|
};
|
|
346
347
|
}
|
|
347
348
|
//#endregion
|
|
349
|
+
//#region src/shared/session-info.ts
|
|
350
|
+
const SKILL_CONTENT_RE = /^\s*<skill_content\s+name="([^"]+)">/;
|
|
351
|
+
function asRecord(value) {
|
|
352
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
353
|
+
}
|
|
354
|
+
function nonEmptyString(value) {
|
|
355
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
356
|
+
}
|
|
357
|
+
function nonNegativeInt(value) {
|
|
358
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
359
|
+
}
|
|
360
|
+
function positiveInt(value) {
|
|
361
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : void 0;
|
|
362
|
+
}
|
|
363
|
+
function firstTextOf(content) {
|
|
364
|
+
if (!Array.isArray(content)) return "";
|
|
365
|
+
for (const item of content) {
|
|
366
|
+
const block = asRecord(item);
|
|
367
|
+
if (block?.type === "text") return typeof block.text === "string" ? block.text : "";
|
|
368
|
+
}
|
|
369
|
+
return "";
|
|
370
|
+
}
|
|
371
|
+
function toolSkillName(message) {
|
|
372
|
+
if (message === null || message.isError === true) return void 0;
|
|
373
|
+
return SKILL_CONTENT_RE.exec(firstTextOf(message.content))?.[1];
|
|
374
|
+
}
|
|
375
|
+
function invokedSkillName(type, data) {
|
|
376
|
+
const source = asRecord((type === "developer/message" ? asRecord(data?.message) : data)?.source);
|
|
377
|
+
if (source?.kind !== "skill-invocation") return void 0;
|
|
378
|
+
return nonEmptyString(source.name);
|
|
379
|
+
}
|
|
380
|
+
function replaceRangeOf(surfaceOp) {
|
|
381
|
+
const op = asRecord(surfaceOp);
|
|
382
|
+
if (op?.op !== "replace") return null;
|
|
383
|
+
const startSeq = nonNegativeInt(op.startSeq);
|
|
384
|
+
const endSeq = nonNegativeInt(op.endSeq);
|
|
385
|
+
if (startSeq === void 0 || endSeq === void 0 || endSeq < startSeq) return null;
|
|
386
|
+
return {
|
|
387
|
+
startSeq,
|
|
388
|
+
endSeq
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
function isSeqShadowed(seq, replacedRanges, shadowedSet) {
|
|
392
|
+
if (shadowedSet.has(seq)) return true;
|
|
393
|
+
for (const range of replacedRanges) if (seq >= range.startSeq && seq <= range.endSeq) return true;
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
function deduplicateSkills(nodes) {
|
|
397
|
+
const byName = new Map();
|
|
398
|
+
for (const node of nodes) byName.set(node.name, node);
|
|
399
|
+
return [...byName.values()];
|
|
400
|
+
}
|
|
401
|
+
function projectSkills(events) {
|
|
402
|
+
let windowStartSeq = null;
|
|
403
|
+
let currentTurn;
|
|
404
|
+
const rawNodes = [];
|
|
405
|
+
const replacedRanges = [];
|
|
406
|
+
const shadowedSeqs = [];
|
|
407
|
+
const shadowedSet = new Set();
|
|
408
|
+
for (const raw of events) {
|
|
409
|
+
const ev = asRecord(raw);
|
|
410
|
+
if (ev === null) continue;
|
|
411
|
+
const seq = nonNegativeInt(ev.seq);
|
|
412
|
+
if (seq !== void 0 && (windowStartSeq === null || seq < windowStartSeq)) windowStartSeq = seq;
|
|
413
|
+
const range = replaceRangeOf(ev.surfaceOp);
|
|
414
|
+
if (range !== null) replacedRanges.push(range);
|
|
415
|
+
const data = asRecord(ev.data);
|
|
416
|
+
const turnInEvent = positiveInt(data?.turn);
|
|
417
|
+
if (range === null && turnInEvent !== void 0) currentTurn = turnInEvent;
|
|
418
|
+
const effectiveTurn = turnInEvent ?? currentTurn;
|
|
419
|
+
const type = nonEmptyString(ev.type);
|
|
420
|
+
if (type === "compaction/summary" || type === "compaction/prune") {
|
|
421
|
+
const list = data?.shadowedSeqs;
|
|
422
|
+
if (Array.isArray(list)) for (const item of list) {
|
|
423
|
+
const s = nonNegativeInt(item);
|
|
424
|
+
if (s !== void 0 && !shadowedSet.has(s)) {
|
|
425
|
+
shadowedSet.add(s);
|
|
426
|
+
shadowedSeqs.push(s);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
if (seq === void 0) continue;
|
|
432
|
+
if (type === "user/message" || type === "developer/message") {
|
|
433
|
+
const name = invokedSkillName(type, data);
|
|
434
|
+
if (name !== void 0) rawNodes.push({
|
|
435
|
+
name,
|
|
436
|
+
trigger: "user",
|
|
437
|
+
seq,
|
|
438
|
+
...effectiveTurn === void 0 ? {} : { turn: effectiveTurn }
|
|
439
|
+
});
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
if (type === "tool/result") {
|
|
443
|
+
const name = toolSkillName(asRecord(data?.message));
|
|
444
|
+
if (name !== void 0) rawNodes.push({
|
|
445
|
+
name,
|
|
446
|
+
trigger: "agent",
|
|
447
|
+
seq,
|
|
448
|
+
...effectiveTurn === void 0 ? {} : { turn: effectiveTurn }
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
const surviving = rawNodes.filter((node) => !isSeqShadowed(node.seq, replacedRanges, shadowedSet));
|
|
453
|
+
return {
|
|
454
|
+
skills: deduplicateSkills(surviving),
|
|
455
|
+
nodes: surviving,
|
|
456
|
+
windowStartSeq,
|
|
457
|
+
replacedRanges,
|
|
458
|
+
shadowedSeqs
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
//#endregion
|
|
462
|
+
//#region src/session-info/host.ts
|
|
463
|
+
const SESSION_INFO_PATH = SESSION_INFO_ROUTE;
|
|
464
|
+
const EMPTY_PROJECTION = {
|
|
465
|
+
skills: [],
|
|
466
|
+
nodes: [],
|
|
467
|
+
windowStartSeq: null,
|
|
468
|
+
replacedRanges: [],
|
|
469
|
+
shadowedSeqs: []
|
|
470
|
+
};
|
|
471
|
+
function json(body, status = 200) {
|
|
472
|
+
return new Response(JSON.stringify(body), {
|
|
473
|
+
status,
|
|
474
|
+
headers: { "content-type": "application/json" }
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
async function disposeObservation(observation) {
|
|
478
|
+
if (observation === null || observation === void 0 || typeof observation !== "object") return;
|
|
479
|
+
try {
|
|
480
|
+
const asyncDispose = observation[Symbol.asyncDispose];
|
|
481
|
+
if (typeof asyncDispose === "function") {
|
|
482
|
+
await asyncDispose.call(observation);
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
const syncDispose = observation[Symbol.dispose];
|
|
486
|
+
if (typeof syncDispose === "function") syncDispose.call(observation);
|
|
487
|
+
} catch {}
|
|
488
|
+
}
|
|
489
|
+
async function readAllSessionEvents(ctx, sessionId) {
|
|
490
|
+
const sessions = ctx.get("sessions");
|
|
491
|
+
if (sessions !== null && sessions !== void 0 && typeof sessions.get === "function") try {
|
|
492
|
+
const live = sessions.get(sessionId);
|
|
493
|
+
if (live !== void 0 && typeof live.snapshotEvents === "function") {
|
|
494
|
+
const events = live.snapshotEvents();
|
|
495
|
+
if (Array.isArray(events)) return events;
|
|
496
|
+
}
|
|
497
|
+
} catch {}
|
|
498
|
+
const query = ctx.get("sessionQuery");
|
|
499
|
+
if (query === null || query === void 0 || typeof query.observeSession !== "function") return null;
|
|
500
|
+
let observation;
|
|
501
|
+
try {
|
|
502
|
+
observation = await query.observeSession(sessionId, { projectionMode: "none" });
|
|
503
|
+
const events = observation?.events;
|
|
504
|
+
return Array.isArray(events) ? events : null;
|
|
505
|
+
} catch {
|
|
506
|
+
return null;
|
|
507
|
+
} finally {
|
|
508
|
+
await disposeObservation(observation);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
async function handleSessionInfo(ctx, request) {
|
|
512
|
+
let sessionId;
|
|
513
|
+
try {
|
|
514
|
+
sessionId = (await request.json())?.sessionId;
|
|
515
|
+
} catch {
|
|
516
|
+
return json(EMPTY_PROJECTION, 400);
|
|
517
|
+
}
|
|
518
|
+
if (typeof sessionId !== "string" || sessionId === "") return json(EMPTY_PROJECTION, 400);
|
|
519
|
+
const events = await readAllSessionEvents(ctx, sessionId);
|
|
520
|
+
if (events === null) return json(EMPTY_PROJECTION);
|
|
521
|
+
return json(projectSkills(events));
|
|
522
|
+
}
|
|
523
|
+
function registerSessionInfoRoute(ctx) {
|
|
524
|
+
const connection = ctx.get("connection");
|
|
525
|
+
const register = connection?.fetch?.register;
|
|
526
|
+
if (typeof register !== "function") return () => {};
|
|
527
|
+
const dispose = register.call(connection?.fetch, {
|
|
528
|
+
path: SESSION_INFO_PATH,
|
|
529
|
+
methods: ["POST"],
|
|
530
|
+
requestBody: "buffered",
|
|
531
|
+
fetch: (request) => handleSessionInfo(ctx, request)
|
|
532
|
+
});
|
|
533
|
+
return () => {
|
|
534
|
+
Promise.resolve().then(() => dispose()).catch(() => void 0);
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
//#endregion
|
|
348
538
|
//#region src/index.ts
|
|
349
539
|
const Config = Schema.object({
|
|
350
540
|
findBar: Schema.boolean().default(true).volatile(),
|
|
@@ -352,6 +542,7 @@ const Config = Schema.object({
|
|
|
352
542
|
compactionRow: Schema.boolean().default(true).volatile(),
|
|
353
543
|
suggest: Schema.boolean().default(true).volatile(),
|
|
354
544
|
stepDuration: Schema.boolean().default(true).volatile(),
|
|
545
|
+
sessionInfo: Schema.boolean().default(true).volatile(),
|
|
355
546
|
suggestModel: Schema.string().default("").volatile(),
|
|
356
547
|
suggestReasoning: Schema.string().default("").volatile(),
|
|
357
548
|
suggestPrompt: Schema.string().default("").volatile()
|
|
@@ -363,12 +554,18 @@ function apply(ctx) {
|
|
|
363
554
|
} catch (error) {
|
|
364
555
|
serviceCtx.logger?.warn(`desktop-enhance: suggest route not registered: ${String(error)}`);
|
|
365
556
|
}
|
|
557
|
+
try {
|
|
558
|
+
serviceCtx.effect(() => registerSessionInfoRoute(serviceCtx), "desktop-enhance: session-info route");
|
|
559
|
+
} catch (error) {
|
|
560
|
+
serviceCtx.logger?.warn(`desktop-enhance: session-info route not registered: ${String(error)}`);
|
|
561
|
+
}
|
|
366
562
|
});
|
|
367
563
|
}
|
|
368
564
|
const __test = {
|
|
369
565
|
SUGGEST_PATH,
|
|
370
566
|
SUGGEST_MODELS_PATH,
|
|
371
567
|
SUGGEST_EFFORTS_PATH,
|
|
568
|
+
SESSION_INFO_PATH,
|
|
372
569
|
MODEL_TIMEOUT_MS,
|
|
373
570
|
MAX_OUTPUT_TOKENS,
|
|
374
571
|
buildPrompt,
|
|
@@ -376,7 +573,9 @@ const __test = {
|
|
|
376
573
|
collectText,
|
|
377
574
|
knownNamesOf,
|
|
378
575
|
handleSuggest,
|
|
576
|
+
handleSessionInfo,
|
|
379
577
|
registerSuggestRoute,
|
|
578
|
+
registerSessionInfoRoute,
|
|
380
579
|
routeOf,
|
|
381
580
|
quietEffortFor,
|
|
382
581
|
listModels,
|
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.5",
|
|
4
|
+
"description": "DSH Desktop 界面增强:页内查找(Cmd+F)、轮次编号、上下文压缩行常显、建议、每步耗时、会话信息。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./lib/index.js",
|