dsh-desktop-enhance 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/lib/client.js +235 -218
- package/lib/index.d.ts +16 -16
- package/lib/index.js +27 -27
- package/package.json +13 -15
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ Web 版(浏览器里打开的那种)键位是 **`Cmd+Shift+.`** —— `Cmd+
|
|
|
36
36
|
- 展开时自动退回通栏样式(宿主展开时把它变成遮盖头,缩成小胶囊会让正文从两侧透出)
|
|
37
37
|
- 手工 `/compact` 触发的压缩同样适用
|
|
38
38
|
|
|
39
|
-
###
|
|
39
|
+
### 建议
|
|
40
40
|
|
|
41
41
|
一轮结束后,输入框上方出现最多 3 条「下一步可能想问的」提示词(**一行**,窄屏才折行)。它与输入框**左对齐、同宽**:
|
|
42
42
|
|
|
@@ -105,7 +105,7 @@ dsh plugin --profile desktop update dsh-desktop-enhance
|
|
|
105
105
|
|
|
106
106
|
只改插件内容的话,**刷新页面即可**,不必重启。
|
|
107
107
|
|
|
108
|
-
> ⚠️ **例外:如果插件更新里改了「宿主半侧」(`src/index.ts` / `src/
|
|
108
|
+
> ⚠️ **例外:如果插件更新里改了「宿主半侧」(`src/index.ts` / `src/suggest/**`),必须重启 App** —— 刷新页面不够。此时设置卡片会直接把不可用的项**置灰**并提示你重启,而不是等你点了几次之后才报「设置没写进去」。**看到那句提示 = 重启即可解决。**
|
|
109
109
|
|
|
110
110
|
## 开关
|
|
111
111
|
|
|
@@ -113,9 +113,9 @@ dsh plugin --profile desktop update dsh-desktop-enhance
|
|
|
113
113
|
|
|
114
114
|
> 侧栏 **插件** → 插件列表里选中 **`dsh-desktop-enhance`** → 页面里的 **「UI 增强」** 一栏
|
|
115
115
|
|
|
116
|
-
四个开关:**页内查找** / **轮次编号** / **压缩行高亮** /
|
|
116
|
+
四个开关:**页内查找** / **轮次编号** / **压缩行高亮** / **建议**。默认全开,装完与之前行为一致,除非你自己去关。
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
「建议」关掉时,它那三个参数(模型 / 推理强度 / 指令模板)也会一并收起 —— 功能关着时它们不起作用。
|
|
119
119
|
|
|
120
120
|
值写进 profile 的 cordis 配置,**重启后仍然生效**(不是浏览器本地存储)。关掉某一项会**完全回到 DSH 原样**。
|
|
121
121
|
|
|
@@ -124,7 +124,7 @@ dsh plugin --profile desktop update dsh-desktop-enhance
|
|
|
124
124
|
- **只搜已经加载的内容。** 更早的轮次需要点「加载更早」才会进搜索范围,查找条不会替你加载。
|
|
125
125
|
- **`Cmd+F` 只在桌面版注册。** Web 实例上是 `Cmd+Shift+.`。
|
|
126
126
|
- 跳转临时展开的内容,**关掉查找条就复原** —— 这是有意设计,不会把整组工具调用永久摊开。
|
|
127
|
-
-
|
|
127
|
+
- **建议依赖宿主能打模型调用。** 会话还没发过第一次请求、或宿主里 `llm` 服务不在时,建议退化成空列表(页面不报错,也没有提示)—— 这是有意的降级:建议是加分项,不该因为它弹错误。
|
|
128
128
|
- **建议的语言跟着你。** 指令里点名要求「用用户自己在用的语言」,所以中文对话给中文建议;模型不听话时可能混出英文。
|
|
129
129
|
|
|
130
130
|
## 卸载
|
package/lib/client.js
CHANGED
|
@@ -15,10 +15,10 @@ window.__ModuleLoader__.load({
|
|
|
15
15
|
"find.next": "下一个匹配",
|
|
16
16
|
"find.close": "关闭查找",
|
|
17
17
|
"shortcut.find": "在对话中查找",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
18
|
+
"suggest.title": "建议",
|
|
19
|
+
"suggest.loading": "正在想下一轮…",
|
|
20
|
+
"suggest.dismiss": "收起建议",
|
|
21
|
+
"suggest.failed": "没写进输入框(宿主正忙或草稿有冲突),可以再点一次。",
|
|
22
22
|
"settings.title": "UI 增强",
|
|
23
23
|
"settings.description": "逐项开关本插件添加的界面增强。关闭后恢复 DSH 原生外观。",
|
|
24
24
|
"settings.findBar": "页内查找",
|
|
@@ -27,27 +27,27 @@ window.__ModuleLoader__.load({
|
|
|
27
27
|
"settings.turnPrefix.hint": "悬停右侧轨道刻度时,预览卡上显示 #轮次 前缀",
|
|
28
28
|
"settings.compactionRow": "压缩行高亮",
|
|
29
29
|
"settings.compactionRow.hint": "上下文压缩那一行不再折叠隐藏,并显示为醒目的居中胶囊",
|
|
30
|
-
"settings.
|
|
31
|
-
"settings.
|
|
32
|
-
"settings.
|
|
33
|
-
"settings.
|
|
34
|
-
"settings.
|
|
35
|
-
"settings.
|
|
36
|
-
"settings.
|
|
37
|
-
"settings.
|
|
38
|
-
"settings.
|
|
39
|
-
"settings.
|
|
40
|
-
"settings.
|
|
41
|
-
"settings.
|
|
42
|
-
"settings.
|
|
43
|
-
"settings.
|
|
44
|
-
"settings.
|
|
45
|
-
"settings.
|
|
46
|
-
"settings.
|
|
47
|
-
"settings.
|
|
48
|
-
"settings.
|
|
49
|
-
"settings.
|
|
50
|
-
"settings.
|
|
30
|
+
"settings.suggest": "建议",
|
|
31
|
+
"settings.suggest.hint": "每轮结束后问一次模型,把 1 到 3 条可能的下一轮提示词摆在输入框上方,点一下就写进草稿",
|
|
32
|
+
"settings.suggestModel": "建议用哪个模型",
|
|
33
|
+
"settings.suggestModel.hint": "留空则跟随当前会话的模型;建议选一个非推理的轻量模型,否则每条建议都要等它想完",
|
|
34
|
+
"settings.suggestModel.follow": "跟随当前会话",
|
|
35
|
+
"settings.suggestModel.custom": "手动填写 provider/model",
|
|
36
|
+
"settings.suggestModel.loading": "正在读取可选模型…",
|
|
37
|
+
"settings.suggestModel.unavailable": "这台宿主没有提供模型目录,请手动填写 provider/model。",
|
|
38
|
+
"settings.suggestReasoning": "推理强度",
|
|
39
|
+
"settings.suggestReasoning.hint": "留空表示自动选择该模型最省事的一档(通常等于关闭思考)。推理越强,建议出得越慢。",
|
|
40
|
+
"settings.suggestReasoning.auto": "自动(最省事的一档)",
|
|
41
|
+
"settings.suggestReasoning.needModel": "先选一个模型,才能列出它支持的推理强度。",
|
|
42
|
+
"settings.suggestPrompt": "指令模板",
|
|
43
|
+
"settings.suggestPrompt.hint": "发给模型的那段指令。两个占位符必须保留,否则保存不了。",
|
|
44
|
+
"settings.suggestPrompt.reset": "恢复默认",
|
|
45
|
+
"settings.suggestPrompt.save": "保存",
|
|
46
|
+
"settings.suggestPrompt.saved": "已保存。",
|
|
47
|
+
"settings.suggestPrompt.empty": "模板不能为空。",
|
|
48
|
+
"settings.suggestPrompt.missingPlaceholder": "模板里必须保留 {{MAX_SUGGESTIONS}} 与 {{LABEL_MAX}} 两个占位符。",
|
|
49
|
+
"settings.suggestPrompt.missingFormat": "模板里必须保留输出格式那段(一个 JSON 数组,每条带 \"label\" 与 \"prompt\")。",
|
|
50
|
+
"settings.suggestPrompt.placeholders": "可用占位符:",
|
|
51
51
|
"settings.readOnly": "当前宿主没有可写的设置服务,开关暂不可用;插件按默认(全部开启)运行。",
|
|
52
52
|
"settings.staleHost": "插件已更新,但应用还跑着旧的宿主半侧,这些设置改不动:请重启应用(刷新页面不够)。",
|
|
53
53
|
"settings.writeFailed": "设置没写进去,开关已退回原状态;请重试。"
|
|
@@ -59,10 +59,10 @@ window.__ModuleLoader__.load({
|
|
|
59
59
|
"find.next": "Next match",
|
|
60
60
|
"find.close": "Close find",
|
|
61
61
|
"shortcut.find": "Find in conversation",
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
62
|
+
"suggest.title": "Suggestions",
|
|
63
|
+
"suggest.loading": "Thinking of the next round…",
|
|
64
|
+
"suggest.dismiss": "Dismiss suggestions",
|
|
65
|
+
"suggest.failed": "Nothing was written into the composer (the host is busy, or the draft conflicted). Try again.",
|
|
66
66
|
"settings.title": "UI enhancements",
|
|
67
67
|
"settings.description": "Switch each interface enhancement this plugin adds. Turning one off restores the native DSH look.",
|
|
68
68
|
"settings.findBar": "Find in conversation",
|
|
@@ -71,27 +71,27 @@ window.__ModuleLoader__.load({
|
|
|
71
71
|
"settings.turnPrefix.hint": "Shows a #N prefix on the preview card when hovering the rail marks",
|
|
72
72
|
"settings.compactionRow": "Compaction row highlight",
|
|
73
73
|
"settings.compactionRow.hint": "Keeps the context-compaction row unfolded and shows it as a prominent centred capsule",
|
|
74
|
-
"settings.
|
|
75
|
-
"settings.
|
|
76
|
-
"settings.
|
|
77
|
-
"settings.
|
|
78
|
-
"settings.
|
|
79
|
-
"settings.
|
|
80
|
-
"settings.
|
|
81
|
-
"settings.
|
|
82
|
-
"settings.
|
|
83
|
-
"settings.
|
|
84
|
-
"settings.
|
|
85
|
-
"settings.
|
|
86
|
-
"settings.
|
|
87
|
-
"settings.
|
|
88
|
-
"settings.
|
|
89
|
-
"settings.
|
|
90
|
-
"settings.
|
|
91
|
-
"settings.
|
|
92
|
-
"settings.
|
|
93
|
-
"settings.
|
|
94
|
-
"settings.
|
|
74
|
+
"settings.suggest": "Suggestions",
|
|
75
|
+
"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",
|
|
76
|
+
"settings.suggestModel": "Model for suggestions",
|
|
77
|
+
"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
|
+
"settings.suggestModel.follow": "Follow the current session",
|
|
79
|
+
"settings.suggestModel.custom": "Type a provider/model by hand",
|
|
80
|
+
"settings.suggestModel.loading": "Reading the available models…",
|
|
81
|
+
"settings.suggestModel.unavailable": "This host serves no model catalog; type a provider/model by hand.",
|
|
82
|
+
"settings.suggestReasoning": "Reasoning effort",
|
|
83
|
+
"settings.suggestReasoning.hint": "Empty picks the cheapest effort this model accepts (usually no thinking). More reasoning means slower suggestions.",
|
|
84
|
+
"settings.suggestReasoning.auto": "Automatic (cheapest effort)",
|
|
85
|
+
"settings.suggestReasoning.needModel": "Pick a model first to list the efforts it accepts.",
|
|
86
|
+
"settings.suggestPrompt": "Instruction template",
|
|
87
|
+
"settings.suggestPrompt.hint": "The instruction sent to the model. Both placeholders must stay, or it will not save.",
|
|
88
|
+
"settings.suggestPrompt.reset": "Restore default",
|
|
89
|
+
"settings.suggestPrompt.save": "Save",
|
|
90
|
+
"settings.suggestPrompt.saved": "Saved.",
|
|
91
|
+
"settings.suggestPrompt.empty": "The template must not be empty.",
|
|
92
|
+
"settings.suggestPrompt.missingPlaceholder": "The template must keep both the {{MAX_SUGGESTIONS}} and {{LABEL_MAX}} placeholders.",
|
|
93
|
+
"settings.suggestPrompt.missingFormat": "The template must keep the output-format clause (a JSON array whose entries carry \"label\" and \"prompt\").",
|
|
94
|
+
"settings.suggestPrompt.placeholders": "Available placeholders: ",
|
|
95
95
|
"settings.readOnly": "This host has no writable settings service, so the switches are unavailable; the plugin runs with its defaults (all on).",
|
|
96
96
|
"settings.staleHost": "The plugin updated, but the app is still running the old host half, so these settings cannot change: restart the app (refreshing the page is not enough).",
|
|
97
97
|
"settings.writeFailed": "The setting did not save; the switch went back. Try again."
|
|
@@ -104,15 +104,16 @@ window.__ModuleLoader__.load({
|
|
|
104
104
|
const notify = () => {
|
|
105
105
|
for (const listener of listeners) listener(open);
|
|
106
106
|
};
|
|
107
|
+
const set = (next) => {
|
|
108
|
+
if (open === next) return;
|
|
109
|
+
open = next;
|
|
110
|
+
notify();
|
|
111
|
+
};
|
|
107
112
|
return {
|
|
108
113
|
isOpen: () => open,
|
|
109
|
-
set
|
|
110
|
-
if (open === next) return;
|
|
111
|
-
open = next;
|
|
112
|
-
notify();
|
|
113
|
-
},
|
|
114
|
+
set,
|
|
114
115
|
toggle() {
|
|
115
|
-
|
|
116
|
+
set(!open);
|
|
116
117
|
},
|
|
117
118
|
subscribe(listener) {
|
|
118
119
|
listeners.add(listener);
|
|
@@ -347,21 +348,21 @@ window.__ModuleLoader__.load({
|
|
|
347
348
|
const SETTINGS_NS = "desktop-enhance";
|
|
348
349
|
const PACKAGE_NAME = "dsh-desktop-enhance";
|
|
349
350
|
const TEXT_FIELDS = [
|
|
350
|
-
"
|
|
351
|
-
"
|
|
352
|
-
"
|
|
351
|
+
"suggestModel",
|
|
352
|
+
"suggestReasoning",
|
|
353
|
+
"suggestPrompt"
|
|
353
354
|
];
|
|
354
355
|
const GATES = {
|
|
355
356
|
findBar: "data-desktop-enhance-off-find-bar",
|
|
356
357
|
turnPrefix: "data-desktop-enhance-off-turn-prefix",
|
|
357
358
|
compactionRow: "data-desktop-enhance-off-compaction-row",
|
|
358
|
-
|
|
359
|
+
suggest: "data-desktop-enhance-off-suggest"
|
|
359
360
|
};
|
|
360
361
|
const FIELDS = [
|
|
361
362
|
"findBar",
|
|
362
363
|
"turnPrefix",
|
|
363
364
|
"compactionRow",
|
|
364
|
-
"
|
|
365
|
+
"suggest"
|
|
365
366
|
];
|
|
366
367
|
const ALL_FIELDS = [...FIELDS, ...TEXT_FIELDS];
|
|
367
368
|
function flagOn(value, field) {
|
|
@@ -374,6 +375,25 @@ window.__ModuleLoader__.load({
|
|
|
374
375
|
const raw = value[field];
|
|
375
376
|
return typeof raw === "string" ? raw.trim() : "";
|
|
376
377
|
}
|
|
378
|
+
const NO_PREFERENCE = {
|
|
379
|
+
model: "",
|
|
380
|
+
reasoning: "",
|
|
381
|
+
prompt: ""
|
|
382
|
+
};
|
|
383
|
+
const PREFERENCE_KEY = {
|
|
384
|
+
suggestModel: "model",
|
|
385
|
+
suggestReasoning: "reasoning",
|
|
386
|
+
suggestPrompt: "prompt"
|
|
387
|
+
};
|
|
388
|
+
function preferenceOf(value) {
|
|
389
|
+
const out = {
|
|
390
|
+
model: "",
|
|
391
|
+
reasoning: "",
|
|
392
|
+
prompt: ""
|
|
393
|
+
};
|
|
394
|
+
for (const field of TEXT_FIELDS) out[PREFERENCE_KEY[field]] = textOf(value, field);
|
|
395
|
+
return out;
|
|
396
|
+
}
|
|
377
397
|
function applyGates(value, root) {
|
|
378
398
|
for (const field of FIELDS) {
|
|
379
399
|
const gate = GATES[field];
|
|
@@ -406,8 +426,8 @@ window.__ModuleLoader__.load({
|
|
|
406
426
|
}
|
|
407
427
|
//#endregion
|
|
408
428
|
//#region src/shared/route.ts
|
|
409
|
-
const
|
|
410
|
-
const
|
|
429
|
+
const SUGGEST_ROUTE = "/api/desktop-enhance/suggest";
|
|
430
|
+
const SUGGEST_MODELS_ROUTE = "/api/desktop-enhance/suggest-models";
|
|
411
431
|
//#endregion
|
|
412
432
|
//#region src/client/settings/catalog.ts
|
|
413
433
|
function parseModelCatalog(body) {
|
|
@@ -463,7 +483,7 @@ window.__ModuleLoader__.load({
|
|
|
463
483
|
}
|
|
464
484
|
const catalogCache = createCatalogCache();
|
|
465
485
|
const CACHE_MS = 3e4;
|
|
466
|
-
const
|
|
486
|
+
const SUGGEST_MODELS_URL = SUGGEST_MODELS_ROUTE;
|
|
467
487
|
function createCatalogCache(now = () => Date.now()) {
|
|
468
488
|
const hits = new Map();
|
|
469
489
|
const pending = new Map();
|
|
@@ -723,9 +743,9 @@ window.__ModuleLoader__.load({
|
|
|
723
743
|
className: "de-note",
|
|
724
744
|
role: "alert"
|
|
725
745
|
}, t("settings.staleHost") + "(" + drifted.map((field) => labelOf(t, field)).join("、") + ")") : null;
|
|
726
|
-
const
|
|
727
|
-
return h("div", { "data-desktop-enhance-settings": "" }, h("div", {}, h("div", { className: "de-head-title" }, t("settings.title")), h("div", { className: "de-head-desc" }, t("settings.description"))), ...items,
|
|
728
|
-
key: "
|
|
746
|
+
const showSuggest = flagOn(value, "suggest") || readOnly;
|
|
747
|
+
return h("div", { "data-desktop-enhance-settings": "" }, h("div", {}, h("div", { className: "de-head-title" }, t("settings.title")), h("div", { className: "de-head-desc" }, t("settings.description"))), ...items, showSuggest ? h(SuggestSettings, {
|
|
748
|
+
key: "suggest",
|
|
729
749
|
t,
|
|
730
750
|
value,
|
|
731
751
|
busy,
|
|
@@ -734,41 +754,41 @@ window.__ModuleLoader__.load({
|
|
|
734
754
|
drifted
|
|
735
755
|
}) : null, note);
|
|
736
756
|
}
|
|
737
|
-
function
|
|
738
|
-
const model = textOf(value, "
|
|
739
|
-
const reasoning = textOf(value, "
|
|
740
|
-
const prompt = textOf(value, "
|
|
741
|
-
const modelDisabled = readOnly || busy.includes("
|
|
742
|
-
const effortDisabled = readOnly || busy.includes("
|
|
743
|
-
const promptDisabled = readOnly || busy.includes("
|
|
744
|
-
return h("div", { className: "de-
|
|
757
|
+
function SuggestSettings({ t, value, busy, readOnly, write, drifted }) {
|
|
758
|
+
const model = textOf(value, "suggestModel");
|
|
759
|
+
const reasoning = textOf(value, "suggestReasoning");
|
|
760
|
+
const prompt = textOf(value, "suggestPrompt");
|
|
761
|
+
const modelDisabled = readOnly || busy.includes("suggestModel") || drifted.includes("suggestModel");
|
|
762
|
+
const effortDisabled = readOnly || busy.includes("suggestReasoning") || drifted.includes("suggestReasoning");
|
|
763
|
+
const promptDisabled = readOnly || busy.includes("suggestPrompt") || drifted.includes("suggestPrompt");
|
|
764
|
+
return h("div", { className: "de-suggest-settings" }, [
|
|
745
765
|
h("div", {
|
|
746
766
|
className: "de-item de-item-block",
|
|
747
767
|
key: "model"
|
|
748
|
-
}, h("div", { className: "de-text" }, h("div", { className: "de-title" }, t("settings.
|
|
768
|
+
}, h("div", { className: "de-text" }, h("div", { className: "de-title" }, t("settings.suggestModel")), h("div", { className: "de-desc" }, t("settings.suggestModel.hint"))), h(ModelPicker, {
|
|
749
769
|
model,
|
|
750
770
|
t,
|
|
751
771
|
disabled: modelDisabled,
|
|
752
|
-
onPick: (id) => write("
|
|
772
|
+
onPick: (id) => write("suggestModel", id)
|
|
753
773
|
})),
|
|
754
774
|
h("div", {
|
|
755
775
|
className: "de-item de-item-block",
|
|
756
776
|
key: "reasoning"
|
|
757
|
-
}, h("div", { className: "de-text" }, h("div", { className: "de-title" }, t("settings.
|
|
777
|
+
}, h("div", { className: "de-text" }, h("div", { className: "de-title" }, t("settings.suggestReasoning")), h("div", { className: "de-desc" }, t("settings.suggestReasoning.hint"))), h(EffortPicker, {
|
|
758
778
|
model,
|
|
759
779
|
reasoning,
|
|
760
780
|
t,
|
|
761
781
|
disabled: effortDisabled,
|
|
762
|
-
onPick: (id) => write("
|
|
782
|
+
onPick: (id) => write("suggestReasoning", id)
|
|
763
783
|
})),
|
|
764
784
|
h("div", {
|
|
765
785
|
className: "de-item de-item-block",
|
|
766
786
|
key: "prompt"
|
|
767
|
-
}, h("div", { className: "de-text" }, h("div", { className: "de-title" }, t("settings.
|
|
787
|
+
}, h("div", { className: "de-text" }, h("div", { className: "de-title" }, t("settings.suggestPrompt")), h("div", { className: "de-desc" }, t("settings.suggestPrompt.hint"))), h(PromptEditor, {
|
|
768
788
|
prompt,
|
|
769
789
|
t,
|
|
770
790
|
readOnly: promptDisabled,
|
|
771
|
-
onSave: (text) => write("
|
|
791
|
+
onSave: (text) => write("suggestPrompt", text)
|
|
772
792
|
}))
|
|
773
793
|
]);
|
|
774
794
|
}
|
|
@@ -776,7 +796,7 @@ window.__ModuleLoader__.load({
|
|
|
776
796
|
const [catalog, setCatalog] = React.useState(null);
|
|
777
797
|
React.useEffect(() => {
|
|
778
798
|
let live = true;
|
|
779
|
-
catalogCache.get(
|
|
799
|
+
catalogCache.get(SUGGEST_MODELS_URL, globalThis.fetch).then((body) => {
|
|
780
800
|
if (live) setCatalog(parseModelCatalog(body));
|
|
781
801
|
}).catch(() => {
|
|
782
802
|
if (live) setCatalog({
|
|
@@ -791,8 +811,8 @@ window.__ModuleLoader__.load({
|
|
|
791
811
|
if (catalog === null || !catalog.available) return h("input", {
|
|
792
812
|
type: "text",
|
|
793
813
|
className: "de-text-input",
|
|
794
|
-
"data-desktop-enhance-field": "
|
|
795
|
-
placeholder: t("settings.
|
|
814
|
+
"data-desktop-enhance-field": "suggestModel",
|
|
815
|
+
placeholder: t("settings.suggestModel.custom"),
|
|
796
816
|
value: model,
|
|
797
817
|
disabled,
|
|
798
818
|
onChange: (event) => {
|
|
@@ -812,7 +832,7 @@ window.__ModuleLoader__.load({
|
|
|
812
832
|
const seen = catalog.models.some((choice) => choice.id === model);
|
|
813
833
|
return h("select", {
|
|
814
834
|
className: "de-select",
|
|
815
|
-
"data-desktop-enhance-field": "
|
|
835
|
+
"data-desktop-enhance-field": "suggestModel",
|
|
816
836
|
value: model,
|
|
817
837
|
disabled,
|
|
818
838
|
onChange: (event) => {
|
|
@@ -823,7 +843,7 @@ window.__ModuleLoader__.load({
|
|
|
823
843
|
h("option", {
|
|
824
844
|
key: "__follow",
|
|
825
845
|
value: ""
|
|
826
|
-
}, t("settings.
|
|
846
|
+
}, t("settings.suggestModel.follow")),
|
|
827
847
|
!seen && model !== "" ? h("option", {
|
|
828
848
|
key: "__kept",
|
|
829
849
|
value: model
|
|
@@ -842,7 +862,7 @@ window.__ModuleLoader__.load({
|
|
|
842
862
|
React.useEffect(() => {
|
|
843
863
|
if (model === "") return void 0;
|
|
844
864
|
let live = true;
|
|
845
|
-
catalogCache.get("/api/desktop-enhance/
|
|
865
|
+
catalogCache.get("/api/desktop-enhance/suggest-efforts?model=" + globalThis.encodeURIComponent(model), globalThis.fetch).then((body) => {
|
|
846
866
|
if (!live) return;
|
|
847
867
|
setState({
|
|
848
868
|
model,
|
|
@@ -862,8 +882,8 @@ window.__ModuleLoader__.load({
|
|
|
862
882
|
if (model === "" || efforts.length === 0) return h("input", {
|
|
863
883
|
type: "text",
|
|
864
884
|
className: "de-text-input",
|
|
865
|
-
"data-desktop-enhance-field": "
|
|
866
|
-
placeholder: model === "" ? t("settings.
|
|
885
|
+
"data-desktop-enhance-field": "suggestReasoning",
|
|
886
|
+
placeholder: model === "" ? t("settings.suggestReasoning.needModel") : t("settings.suggestReasoning.auto"),
|
|
867
887
|
value: reasoning,
|
|
868
888
|
disabled,
|
|
869
889
|
onChange: (event) => {
|
|
@@ -874,7 +894,7 @@ window.__ModuleLoader__.load({
|
|
|
874
894
|
const seen = efforts.some((effort) => effort.id === reasoning);
|
|
875
895
|
return h("select", {
|
|
876
896
|
className: "de-select",
|
|
877
|
-
"data-desktop-enhance-field": "
|
|
897
|
+
"data-desktop-enhance-field": "suggestReasoning",
|
|
878
898
|
value: reasoning,
|
|
879
899
|
disabled,
|
|
880
900
|
onChange: (event) => {
|
|
@@ -885,7 +905,7 @@ window.__ModuleLoader__.load({
|
|
|
885
905
|
h("option", {
|
|
886
906
|
key: "__auto",
|
|
887
907
|
value: ""
|
|
888
|
-
}, t("settings.
|
|
908
|
+
}, t("settings.suggestReasoning.auto")),
|
|
889
909
|
!seen && reasoning !== "" ? h("option", {
|
|
890
910
|
key: "__kept",
|
|
891
911
|
value: reasoning
|
|
@@ -914,7 +934,7 @@ window.__ModuleLoader__.load({
|
|
|
914
934
|
h("textarea", {
|
|
915
935
|
key: "box",
|
|
916
936
|
className: "de-textarea",
|
|
917
|
-
"data-desktop-enhance-field": "
|
|
937
|
+
"data-desktop-enhance-field": "suggestPrompt",
|
|
918
938
|
rows: 8,
|
|
919
939
|
value: draft,
|
|
920
940
|
disabled: readOnly,
|
|
@@ -930,12 +950,12 @@ window.__ModuleLoader__.load({
|
|
|
930
950
|
h("div", {
|
|
931
951
|
key: "meta",
|
|
932
952
|
className: "de-prompt-meta"
|
|
933
|
-
}, t("settings.
|
|
953
|
+
}, t("settings.suggestPrompt.placeholders") + PROMPT_PLACEHOLDERS.map((name) => "{{" + name + "}}").join("、")),
|
|
934
954
|
problem !== null ? h("div", {
|
|
935
955
|
key: "problem",
|
|
936
956
|
className: "de-error",
|
|
937
957
|
role: "alert"
|
|
938
|
-
}, t("settings.
|
|
958
|
+
}, t("settings.suggestPrompt." + problem)) : null,
|
|
939
959
|
h("div", {
|
|
940
960
|
key: "actions",
|
|
941
961
|
className: "de-prompt-actions"
|
|
@@ -946,7 +966,7 @@ window.__ModuleLoader__.load({
|
|
|
946
966
|
"data-desktop-enhance-action": "prompt-save",
|
|
947
967
|
disabled: readOnly || !dirty,
|
|
948
968
|
onClick: save
|
|
949
|
-
}, t("settings.
|
|
969
|
+
}, t("settings.suggestPrompt.save")), h("button", {
|
|
950
970
|
key: "reset",
|
|
951
971
|
type: "button",
|
|
952
972
|
className: "de-button",
|
|
@@ -956,7 +976,7 @@ window.__ModuleLoader__.load({
|
|
|
956
976
|
setDraft(DEFAULT_PROMPT);
|
|
957
977
|
setProblem(null);
|
|
958
978
|
}
|
|
959
|
-
}, t("settings.
|
|
979
|
+
}, t("settings.suggestPrompt.reset"))])
|
|
960
980
|
]);
|
|
961
981
|
}
|
|
962
982
|
//#endregion
|
|
@@ -1041,9 +1061,9 @@ window.__ModuleLoader__.load({
|
|
|
1041
1061
|
});
|
|
1042
1062
|
}
|
|
1043
1063
|
//#endregion
|
|
1044
|
-
//#region src/client/
|
|
1064
|
+
//#region src/client/suggest/trigger.ts
|
|
1045
1065
|
const HIDDEN = { kind: "hidden" };
|
|
1046
|
-
function
|
|
1066
|
+
function suggestView(view, input) {
|
|
1047
1067
|
switch (input.kind) {
|
|
1048
1068
|
case "turnend": return {
|
|
1049
1069
|
kind: "loading",
|
|
@@ -1074,9 +1094,9 @@ window.__ModuleLoader__.load({
|
|
|
1074
1094
|
}
|
|
1075
1095
|
}
|
|
1076
1096
|
function assertNever(input) {
|
|
1077
|
-
throw new Error(`unhandled
|
|
1097
|
+
throw new Error(`unhandled suggest input: ${JSON.stringify(input)}`);
|
|
1078
1098
|
}
|
|
1079
|
-
function
|
|
1099
|
+
function createSuggestStore() {
|
|
1080
1100
|
const views = new Map();
|
|
1081
1101
|
let session;
|
|
1082
1102
|
let published = HIDDEN;
|
|
@@ -1104,14 +1124,21 @@ window.__ModuleLoader__.load({
|
|
|
1104
1124
|
published = now;
|
|
1105
1125
|
for (const listener of listeners) listener();
|
|
1106
1126
|
};
|
|
1127
|
+
const drop = (sessionId) => {
|
|
1128
|
+
if (!views.delete(sessionId)) return;
|
|
1129
|
+
if (sessionId !== session) return;
|
|
1130
|
+
if (published === HIDDEN) return;
|
|
1131
|
+
published = HIDDEN;
|
|
1132
|
+
for (const listener of listeners) listener();
|
|
1133
|
+
};
|
|
1107
1134
|
return {
|
|
1108
1135
|
get: () => viewOf(session),
|
|
1109
1136
|
dispatch(sessionId, input) {
|
|
1110
|
-
put(sessionId,
|
|
1137
|
+
put(sessionId, suggestView(viewOf(sessionId), input));
|
|
1111
1138
|
},
|
|
1112
1139
|
offer(sessionId, turn, raw) {
|
|
1113
1140
|
const items = normalizeEntries(Array.isArray(raw) ? raw : [], null);
|
|
1114
|
-
put(sessionId,
|
|
1141
|
+
put(sessionId, suggestView(viewOf(sessionId), {
|
|
1115
1142
|
kind: "reply",
|
|
1116
1143
|
turn,
|
|
1117
1144
|
items
|
|
@@ -1133,15 +1160,9 @@ window.__ModuleLoader__.load({
|
|
|
1133
1160
|
for (const listener of listeners) listener();
|
|
1134
1161
|
},
|
|
1135
1162
|
currentSession: () => session,
|
|
1136
|
-
forget
|
|
1137
|
-
if (!views.delete(sessionId)) return;
|
|
1138
|
-
if (sessionId !== session) return;
|
|
1139
|
-
if (published === HIDDEN) return;
|
|
1140
|
-
published = HIDDEN;
|
|
1141
|
-
for (const listener of listeners) listener();
|
|
1142
|
-
},
|
|
1163
|
+
forget: drop,
|
|
1143
1164
|
forgetCurrent() {
|
|
1144
|
-
if (session !== void 0)
|
|
1165
|
+
if (session !== void 0) drop(session);
|
|
1145
1166
|
},
|
|
1146
1167
|
subscribe(listener) {
|
|
1147
1168
|
listeners.add(listener);
|
|
@@ -1150,8 +1171,50 @@ window.__ModuleLoader__.load({
|
|
|
1150
1171
|
};
|
|
1151
1172
|
}
|
|
1152
1173
|
//#endregion
|
|
1153
|
-
//#region src/client/
|
|
1154
|
-
const
|
|
1174
|
+
//#region src/client/suggest/watch.ts
|
|
1175
|
+
const WARM_MS = 12e4;
|
|
1176
|
+
function runningIn(snapshot) {
|
|
1177
|
+
const ids = snapshot?.ids;
|
|
1178
|
+
const byId = snapshot?.byId;
|
|
1179
|
+
if (!Array.isArray(ids) || byId === null || typeof byId !== "object") return [];
|
|
1180
|
+
return ids.filter((id) => byId[id]?.running === true);
|
|
1181
|
+
}
|
|
1182
|
+
function sessionsToWatch(snapshot, current, warm = []) {
|
|
1183
|
+
const out = [];
|
|
1184
|
+
const seen = new Set();
|
|
1185
|
+
const add = (id) => {
|
|
1186
|
+
if (typeof id !== "string" || id === "" || seen.has(id)) return;
|
|
1187
|
+
seen.add(id);
|
|
1188
|
+
out.push(id);
|
|
1189
|
+
};
|
|
1190
|
+
add(current);
|
|
1191
|
+
for (const id of runningIn(snapshot)) add(id);
|
|
1192
|
+
for (const id of warm) add(id);
|
|
1193
|
+
return out;
|
|
1194
|
+
}
|
|
1195
|
+
function createWarmth(windowMs = WARM_MS) {
|
|
1196
|
+
const until = new Map();
|
|
1197
|
+
return {
|
|
1198
|
+
renew(id, at) {
|
|
1199
|
+
until.set(id, at + windowMs);
|
|
1200
|
+
},
|
|
1201
|
+
live(at) {
|
|
1202
|
+
const out = [];
|
|
1203
|
+
for (const [id, deadline] of until) if (deadline > at) out.push(id);
|
|
1204
|
+
return out;
|
|
1205
|
+
},
|
|
1206
|
+
sweep(at) {
|
|
1207
|
+
for (const [id, deadline] of until) if (deadline <= at) until.delete(id);
|
|
1208
|
+
},
|
|
1209
|
+
held: () => until.size,
|
|
1210
|
+
clear() {
|
|
1211
|
+
until.clear();
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
//#endregion
|
|
1216
|
+
//#region src/client/suggest/bridge.ts
|
|
1217
|
+
const SUGGEST_URL = SUGGEST_ROUTE;
|
|
1155
1218
|
function turnEnded(entries) {
|
|
1156
1219
|
let turn = null;
|
|
1157
1220
|
for (const entry of entries) {
|
|
@@ -1180,26 +1243,9 @@ window.__ModuleLoader__.load({
|
|
|
1180
1243
|
}
|
|
1181
1244
|
return turn;
|
|
1182
1245
|
}
|
|
1183
|
-
const NO_PREFERENCE = {
|
|
1184
|
-
model: "",
|
|
1185
|
-
reasoning: "",
|
|
1186
|
-
prompt: ""
|
|
1187
|
-
};
|
|
1188
|
-
function preferenceOf(value) {
|
|
1189
|
-
const source = value !== null && typeof value === "object" ? value : {};
|
|
1190
|
-
const text = (key) => {
|
|
1191
|
-
const raw = source[key];
|
|
1192
|
-
return typeof raw === "string" ? raw.trim() : "";
|
|
1193
|
-
};
|
|
1194
|
-
return {
|
|
1195
|
-
model: text("nextModel"),
|
|
1196
|
-
reasoning: text("nextReasoning"),
|
|
1197
|
-
prompt: text("nextPrompt")
|
|
1198
|
-
};
|
|
1199
|
-
}
|
|
1200
1246
|
async function requestSuggestions(sessionId, fetchImpl, signal, preference = NO_PREFERENCE) {
|
|
1201
1247
|
try {
|
|
1202
|
-
const response = await fetchImpl(
|
|
1248
|
+
const response = await fetchImpl(SUGGEST_URL, {
|
|
1203
1249
|
method: "POST",
|
|
1204
1250
|
headers: { "content-type": "application/json" },
|
|
1205
1251
|
body: JSON.stringify({
|
|
@@ -1212,7 +1258,7 @@ window.__ModuleLoader__.load({
|
|
|
1212
1258
|
});
|
|
1213
1259
|
if (!response.ok) return [];
|
|
1214
1260
|
const body = await response.json();
|
|
1215
|
-
if (body.diag !== void 0 && body.diag !== null) globalThis.console?.info?.("[desktop-enhance]
|
|
1261
|
+
if (body.diag !== void 0 && body.diag !== null) globalThis.console?.info?.("[desktop-enhance] suggest", body.diag);
|
|
1216
1262
|
return Array.isArray(body.items) ? body.items : [];
|
|
1217
1263
|
} catch {
|
|
1218
1264
|
return [];
|
|
@@ -1258,40 +1304,21 @@ window.__ModuleLoader__.load({
|
|
|
1258
1304
|
reference.release();
|
|
1259
1305
|
};
|
|
1260
1306
|
}
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
const add = (id) => {
|
|
1266
|
-
if (typeof id !== "string" || id === "" || seen.has(id)) return;
|
|
1267
|
-
seen.add(id);
|
|
1268
|
-
out.push(id);
|
|
1269
|
-
};
|
|
1270
|
-
add(current);
|
|
1271
|
-
const ids = snapshot?.ids;
|
|
1272
|
-
const byId = snapshot?.byId;
|
|
1273
|
-
if (Array.isArray(ids) && byId !== null && typeof byId === "object") {
|
|
1274
|
-
for (const id of ids) if (byId[id]?.running === true) add(id);
|
|
1275
|
-
}
|
|
1276
|
-
for (const [id, until] of warm) if (until > now) add(id);
|
|
1277
|
-
return out;
|
|
1278
|
-
}
|
|
1279
|
-
function runningIn(snapshot) {
|
|
1280
|
-
const ids = snapshot?.ids;
|
|
1281
|
-
const byId = snapshot?.byId;
|
|
1282
|
-
if (!Array.isArray(ids) || byId === null || typeof byId !== "object") return [];
|
|
1283
|
-
return ids.filter((id) => byId[id]?.running === true);
|
|
1307
|
+
function defaultSchedule(tick, everyMs) {
|
|
1308
|
+
const handle = globalThis.setInterval(tick, everyMs);
|
|
1309
|
+
handle?.unref?.();
|
|
1310
|
+
return () => globalThis.clearInterval(handle);
|
|
1284
1311
|
}
|
|
1285
|
-
function
|
|
1312
|
+
function createSuggestWatcher(getSessions, store, options = {}) {
|
|
1313
|
+
const { fetchImpl = globalThis.fetch, getPreference = () => NO_PREFERENCE, isOn = () => true, now = () => Date.now(), schedule = defaultSchedule } = options;
|
|
1286
1314
|
const refs = new Map();
|
|
1287
1315
|
let current;
|
|
1288
|
-
const
|
|
1316
|
+
const warmth = createWarmth();
|
|
1289
1317
|
let stopped = false;
|
|
1290
1318
|
let catalogStop;
|
|
1291
1319
|
let syncing = false;
|
|
1292
1320
|
let redoSync = false;
|
|
1293
1321
|
let syncQueued = false;
|
|
1294
|
-
const now = () => Date.now();
|
|
1295
1322
|
const sync = () => {
|
|
1296
1323
|
if (stopped) return;
|
|
1297
1324
|
if (syncing) {
|
|
@@ -1313,7 +1340,8 @@ window.__ModuleLoader__.load({
|
|
|
1313
1340
|
if (!isOn()) {
|
|
1314
1341
|
for (const stop of refs.values()) stop();
|
|
1315
1342
|
refs.clear();
|
|
1316
|
-
|
|
1343
|
+
warmth.clear();
|
|
1344
|
+
store.forgetCurrent();
|
|
1317
1345
|
return;
|
|
1318
1346
|
}
|
|
1319
1347
|
const catalog = getSessions()?.list;
|
|
@@ -1322,9 +1350,9 @@ window.__ModuleLoader__.load({
|
|
|
1322
1350
|
onCatalogChange();
|
|
1323
1351
|
});
|
|
1324
1352
|
const at = now();
|
|
1325
|
-
for (const id of runningIn(snapshot))
|
|
1326
|
-
|
|
1327
|
-
const want = snapshot === null ? current === void 0 ? [] : [current] : sessionsToWatch(snapshot, current,
|
|
1353
|
+
for (const id of runningIn(snapshot)) warmth.renew(id, at);
|
|
1354
|
+
warmth.sweep(at);
|
|
1355
|
+
const want = snapshot === null ? current === void 0 ? [] : [current] : sessionsToWatch(snapshot, current, warmth.live(at));
|
|
1328
1356
|
const wanted = new Set(want);
|
|
1329
1357
|
for (const [id, stop] of refs) {
|
|
1330
1358
|
if (wanted.has(id)) continue;
|
|
@@ -1334,7 +1362,7 @@ window.__ModuleLoader__.load({
|
|
|
1334
1362
|
for (const id of want) {
|
|
1335
1363
|
if (refs.has(id)) continue;
|
|
1336
1364
|
const stop = watchSession(getSessions, id, store, fetchImpl, getPreference, () => {
|
|
1337
|
-
|
|
1365
|
+
warmth.renew(id, now());
|
|
1338
1366
|
});
|
|
1339
1367
|
if (stop === null) continue;
|
|
1340
1368
|
refs.set(id, stop);
|
|
@@ -1348,10 +1376,9 @@ window.__ModuleLoader__.load({
|
|
|
1348
1376
|
sync();
|
|
1349
1377
|
});
|
|
1350
1378
|
}
|
|
1351
|
-
const
|
|
1379
|
+
const stopSweep = stopped ? void 0 : schedule(() => {
|
|
1352
1380
|
sync();
|
|
1353
1381
|
}, Math.max(1e3, Math.floor(WARM_MS / 4)));
|
|
1354
|
-
sweep?.unref?.();
|
|
1355
1382
|
return {
|
|
1356
1383
|
setCurrent(sessionId) {
|
|
1357
1384
|
if (sessionId === current) return;
|
|
@@ -1362,44 +1389,31 @@ window.__ModuleLoader__.load({
|
|
|
1362
1389
|
sync();
|
|
1363
1390
|
},
|
|
1364
1391
|
watching: () => [...refs.keys()],
|
|
1392
|
+
held: () => warmth.held(),
|
|
1365
1393
|
stop() {
|
|
1366
1394
|
stopped = true;
|
|
1367
1395
|
for (const stop of refs.values()) stop();
|
|
1368
1396
|
refs.clear();
|
|
1369
|
-
|
|
1370
|
-
|
|
1397
|
+
warmth.clear();
|
|
1398
|
+
stopSweep?.();
|
|
1371
1399
|
catalogStop?.();
|
|
1372
1400
|
catalogStop = void 0;
|
|
1373
1401
|
}
|
|
1374
1402
|
};
|
|
1375
1403
|
}
|
|
1376
1404
|
//#endregion
|
|
1377
|
-
//#region src/client/
|
|
1405
|
+
//#region src/client/suggest/dock.ts
|
|
1378
1406
|
function useView(store) {
|
|
1379
1407
|
return React.useSyncExternalStore(store.subscribe, store.get, store.get);
|
|
1380
1408
|
}
|
|
1381
|
-
function
|
|
1382
|
-
return hasSubscription ? subscribed : read();
|
|
1383
|
-
}
|
|
1384
|
-
function NextDock({ store, t, sessionId, inputActions, setCurrent, isOn, subscribeSettings }) {
|
|
1409
|
+
function SuggestDock({ store, t, sessionId, inputActions, setCurrent }) {
|
|
1385
1410
|
const view = useView(store);
|
|
1386
|
-
const [subscribed, setSubscribed] = React.useState(() => isOn?.() ?? true);
|
|
1387
|
-
const enabled = shouldWatch(subscribed, subscribeSettings !== void 0, () => isOn?.() ?? true);
|
|
1388
|
-
React.useEffect(() => {
|
|
1389
|
-
if (subscribeSettings === void 0) return void 0;
|
|
1390
|
-
const read = () => setSubscribed(isOn?.() ?? true);
|
|
1391
|
-
read();
|
|
1392
|
-
return subscribeSettings(read);
|
|
1393
|
-
}, [isOn, subscribeSettings]);
|
|
1394
1411
|
React.useEffect(() => {
|
|
1395
1412
|
store.setSession(sessionId);
|
|
1396
1413
|
}, [sessionId, store]);
|
|
1397
1414
|
React.useEffect(() => {
|
|
1398
1415
|
setCurrent?.(sessionId);
|
|
1399
1416
|
}, [sessionId, setCurrent]);
|
|
1400
|
-
React.useEffect(() => {
|
|
1401
|
-
if (!enabled) store.forgetCurrent();
|
|
1402
|
-
}, [enabled, store]);
|
|
1403
1417
|
const take = React.useCallback((index, prompt) => {
|
|
1404
1418
|
let written = inputActions === void 0;
|
|
1405
1419
|
if (inputActions !== void 0) try {
|
|
@@ -1419,50 +1433,50 @@ window.__ModuleLoader__.load({
|
|
|
1419
1433
|
]);
|
|
1420
1434
|
if (view.kind === "hidden") return null;
|
|
1421
1435
|
const head = h("div", {
|
|
1422
|
-
className: "de-
|
|
1436
|
+
className: "de-suggest-head",
|
|
1423
1437
|
key: "head"
|
|
1424
1438
|
}, [h("span", {
|
|
1425
|
-
className: "de-
|
|
1439
|
+
className: "de-suggest-title",
|
|
1426
1440
|
key: "title"
|
|
1427
|
-
}, t("
|
|
1441
|
+
}, t("suggest.title")), h("button", {
|
|
1428
1442
|
type: "button",
|
|
1429
1443
|
key: "close",
|
|
1430
|
-
className: "de-
|
|
1431
|
-
"aria-label": t("
|
|
1432
|
-
title: t("
|
|
1444
|
+
className: "de-suggest-close",
|
|
1445
|
+
"aria-label": t("suggest.dismiss"),
|
|
1446
|
+
title: t("suggest.dismiss"),
|
|
1433
1447
|
onClick: () => {
|
|
1434
1448
|
if (sessionId !== void 0) store.dispatch(sessionId, { kind: "dismiss" });
|
|
1435
1449
|
}
|
|
1436
1450
|
}, "✕")]);
|
|
1437
1451
|
if (view.kind === "loading") return h("div", {
|
|
1438
|
-
className: "de-
|
|
1439
|
-
"data-desktop-enhance": "
|
|
1452
|
+
className: "de-suggest",
|
|
1453
|
+
"data-desktop-enhance": "suggest"
|
|
1440
1454
|
}, [head, h("span", {
|
|
1441
|
-
className: "de-
|
|
1455
|
+
className: "de-suggest-row de-suggest-loading",
|
|
1442
1456
|
key: "row"
|
|
1443
|
-
}, t("
|
|
1457
|
+
}, t("suggest.loading"))]);
|
|
1444
1458
|
const rows = view.items.map((item, index) => h("button", {
|
|
1445
1459
|
type: "button",
|
|
1446
1460
|
key: `${String(index)}:${item.prompt}`,
|
|
1447
|
-
className: "de-
|
|
1461
|
+
className: "de-suggest-row",
|
|
1448
1462
|
"data-used": index === view.used ? "true" : void 0,
|
|
1449
1463
|
title: item.prompt,
|
|
1450
1464
|
onClick: () => take(index, item.prompt)
|
|
1451
1465
|
}, [h("span", {
|
|
1452
|
-
className: "de-
|
|
1466
|
+
className: "de-suggest-num",
|
|
1453
1467
|
key: "n"
|
|
1454
1468
|
}, String(index + 1)), h("span", {
|
|
1455
|
-
className: "de-
|
|
1469
|
+
className: "de-suggest-text",
|
|
1456
1470
|
key: "t"
|
|
1457
1471
|
}, item.label)]));
|
|
1458
1472
|
const notice = view.failed === true ? h("div", {
|
|
1459
|
-
className: "de-
|
|
1473
|
+
className: "de-suggest-error",
|
|
1460
1474
|
key: "failed",
|
|
1461
1475
|
role: "alert"
|
|
1462
|
-
}, t("
|
|
1476
|
+
}, t("suggest.failed")) : null;
|
|
1463
1477
|
return h("div", {
|
|
1464
|
-
className: "de-
|
|
1465
|
-
"data-desktop-enhance": "
|
|
1478
|
+
className: "de-suggest",
|
|
1479
|
+
"data-desktop-enhance": "suggest"
|
|
1466
1480
|
}, [
|
|
1467
1481
|
head,
|
|
1468
1482
|
...rows,
|
|
@@ -1471,7 +1485,7 @@ window.__ModuleLoader__.load({
|
|
|
1471
1485
|
}
|
|
1472
1486
|
//#endregion
|
|
1473
1487
|
//#region \0dsh-desktop-enhance-css:/Users/lijiechengbj/projects/AI-agents/dsh-desktop-enhance/src/client/styles/enhance.css.mjs
|
|
1474
|
-
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-next-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-next-steps] [data-desktop-enhance='next'] {\n display: none !important;\n}\n:root:not([data-desktop-enhance-off-next-steps]) .de-next {\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-next-steps]) .de-next-head {\n align-items: center;\n display: flex;\n flex: none;\n gap: 2px;\n}\n\n:root:not([data-desktop-enhance-off-next-steps]) .de-next-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-next-steps]) .de-next-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-next-steps]) .de-next-close:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n:root:not([data-desktop-enhance-off-next-steps]) .de-next-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-next-steps]) .de-next-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-next-steps]) .de-next-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-next-steps]) .de-next-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-next-steps]) .de-next-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-next-steps]) .de-next-loading {\n border-style: dashed;\n color: var(--dsw-alias-label-secondary);\n cursor: default;\n}\n\n:root:not([data-desktop-enhance-off-next-steps]) .de-next-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";
|
|
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";
|
|
1475
1489
|
//#endregion
|
|
1476
1490
|
//#region src/client/index.tsx
|
|
1477
1491
|
const inject = [
|
|
@@ -1544,31 +1558,33 @@ window.__ModuleLoader__.load({
|
|
|
1544
1558
|
}, SettingsRow))), "desktop-enhance: plugin page card");
|
|
1545
1559
|
});
|
|
1546
1560
|
installTurnPrefix(ctx);
|
|
1547
|
-
const
|
|
1548
|
-
const
|
|
1561
|
+
const suggestStore = createSuggestStore();
|
|
1562
|
+
const suggestWatcher = createSuggestWatcher(() => ctx.get("sessions"), suggestStore, {
|
|
1563
|
+
fetchImpl: globalThis.fetch,
|
|
1564
|
+
getPreference: () => preferenceOf(settings.get().value),
|
|
1565
|
+
isOn: () => flagOn(settings.get().value, "suggest")
|
|
1566
|
+
});
|
|
1549
1567
|
ctx.effect(() => {
|
|
1550
1568
|
const off = settings.subscribe(() => {
|
|
1551
|
-
|
|
1569
|
+
suggestWatcher.refresh();
|
|
1552
1570
|
});
|
|
1553
1571
|
return () => {
|
|
1554
1572
|
off();
|
|
1555
|
-
|
|
1573
|
+
suggestWatcher.stop();
|
|
1556
1574
|
};
|
|
1557
|
-
}, "desktop-enhance:
|
|
1575
|
+
}, "desktop-enhance: suggest watcher");
|
|
1558
1576
|
ctx.effect(() => ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
|
|
1559
1577
|
name: "conversation.input.dock",
|
|
1560
|
-
id: "desktop-enhance-
|
|
1578
|
+
id: "desktop-enhance-suggest",
|
|
1561
1579
|
order: 30,
|
|
1562
1580
|
locale: NS,
|
|
1563
1581
|
inject: (sessionId) => ({
|
|
1564
|
-
store:
|
|
1565
|
-
setCurrent: (id) =>
|
|
1582
|
+
store: suggestStore,
|
|
1583
|
+
setCurrent: (id) => suggestWatcher.setCurrent(id),
|
|
1566
1584
|
sessionId,
|
|
1567
|
-
isOn: () => flagOn(settings.get().value, "nextSteps"),
|
|
1568
|
-
subscribeSettings: (listener) => settings.subscribe(listener),
|
|
1569
1585
|
getPreference: () => preferenceOf(settings.get().value)
|
|
1570
1586
|
})
|
|
1571
|
-
},
|
|
1587
|
+
}, SuggestDock)), "desktop-enhance: suggest dock");
|
|
1572
1588
|
ctx.effect(() => ctx.slots.inject("shell.overlay", () => ctx.slots.register({
|
|
1573
1589
|
name: "shell.overlay",
|
|
1574
1590
|
id: "desktop-enhance-find",
|
|
@@ -1638,21 +1654,22 @@ window.__ModuleLoader__.load({
|
|
|
1638
1654
|
flagOn,
|
|
1639
1655
|
applyGates,
|
|
1640
1656
|
createSettingsStore,
|
|
1641
|
-
|
|
1657
|
+
suggestView,
|
|
1642
1658
|
HIDDEN,
|
|
1643
|
-
|
|
1644
|
-
|
|
1659
|
+
createSuggestStore,
|
|
1660
|
+
SuggestDock,
|
|
1645
1661
|
watchSession,
|
|
1646
1662
|
sessionsToWatch,
|
|
1647
1663
|
runningIn,
|
|
1648
1664
|
WARM_MS,
|
|
1649
|
-
|
|
1665
|
+
createWarmth,
|
|
1666
|
+
createSuggestWatcher,
|
|
1650
1667
|
MAX_BUCKETS: 8,
|
|
1668
|
+
createFindStore,
|
|
1651
1669
|
turnEnded,
|
|
1652
1670
|
turnStarted,
|
|
1653
1671
|
requestSuggestions,
|
|
1654
|
-
|
|
1655
|
-
shouldWatch,
|
|
1672
|
+
SUGGEST_URL,
|
|
1656
1673
|
clean,
|
|
1657
1674
|
parseSuggestions,
|
|
1658
1675
|
namesKnownCommand,
|
|
@@ -1676,7 +1693,7 @@ window.__ModuleLoader__.load({
|
|
|
1676
1693
|
parseEfforts,
|
|
1677
1694
|
catalogCache,
|
|
1678
1695
|
CACHE_MS,
|
|
1679
|
-
|
|
1696
|
+
SuggestSettings,
|
|
1680
1697
|
ModelPicker,
|
|
1681
1698
|
zh,
|
|
1682
1699
|
en,
|
package/lib/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import Schema from "@deepseek-ai/schemastery";
|
|
|
2
2
|
//#region src/shared/suggest.d.ts
|
|
3
3
|
declare function buildPrompt(template?: string): string;
|
|
4
4
|
//#endregion
|
|
5
|
-
//#region src/
|
|
5
|
+
//#region src/suggest/host.d.ts
|
|
6
6
|
interface HostContext {
|
|
7
7
|
get(name: string): unknown;
|
|
8
8
|
inject(services: readonly string[], callback: (ctx: HostContext) => void): unknown;
|
|
@@ -66,7 +66,7 @@ declare function routeOf(session: HostSession): {
|
|
|
66
66
|
} | null;
|
|
67
67
|
declare function buildMessages(history: readonly HostMessage[], instruction: string): HostMessage[];
|
|
68
68
|
declare function knownNamesOf(messages: readonly HostMessage[]): ReadonlySet<string> | null;
|
|
69
|
-
declare function
|
|
69
|
+
declare function handleSuggest(ctx: HostContext, request: Request, timeoutMs?: number): Promise<Response>;
|
|
70
70
|
declare function quietEffortFor(llm: HostLlm, route: {
|
|
71
71
|
readonly provider: string;
|
|
72
72
|
readonly model: string;
|
|
@@ -88,39 +88,39 @@ declare function listEfforts(ctx: HostContext, provider: string, model: string):
|
|
|
88
88
|
}[];
|
|
89
89
|
defaultEffort: string | null;
|
|
90
90
|
}>;
|
|
91
|
-
declare function
|
|
91
|
+
declare function registerSuggestRoute(ctx: HostContext): () => void;
|
|
92
92
|
//#endregion
|
|
93
93
|
//#region src/index.d.ts
|
|
94
94
|
export declare const Config: Schema<Schemastery.ObjectS<NoInfer<{
|
|
95
95
|
findBar: Schema<boolean, boolean, "volatile-defined">;
|
|
96
96
|
turnPrefix: Schema<boolean, boolean, "volatile-defined">;
|
|
97
97
|
compactionRow: Schema<boolean, boolean, "volatile-defined">;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
suggest: Schema<boolean, boolean, "volatile-defined">;
|
|
99
|
+
suggestModel: Schema<string, string, "volatile-defined">;
|
|
100
|
+
suggestReasoning: Schema<string, string, "volatile-defined">;
|
|
101
|
+
suggestPrompt: Schema<string, string, "volatile-defined">;
|
|
102
102
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
103
103
|
findBar: Schema<boolean, boolean, "volatile-defined">;
|
|
104
104
|
turnPrefix: Schema<boolean, boolean, "volatile-defined">;
|
|
105
105
|
compactionRow: Schema<boolean, boolean, "volatile-defined">;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
suggest: Schema<boolean, boolean, "volatile-defined">;
|
|
107
|
+
suggestModel: Schema<string, string, "volatile-defined">;
|
|
108
|
+
suggestReasoning: Schema<string, string, "volatile-defined">;
|
|
109
|
+
suggestPrompt: Schema<string, string, "volatile-defined">;
|
|
110
110
|
}>>, "plain">;
|
|
111
111
|
export declare function apply(ctx: HostContext): void;
|
|
112
112
|
export declare const __test: {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
SUGGEST_PATH: string;
|
|
114
|
+
SUGGEST_MODELS_PATH: string;
|
|
115
|
+
SUGGEST_EFFORTS_PATH: string;
|
|
116
116
|
MODEL_TIMEOUT_MS: number;
|
|
117
117
|
MAX_OUTPUT_TOKENS: number;
|
|
118
118
|
buildPrompt: typeof buildPrompt;
|
|
119
119
|
buildMessages: typeof buildMessages;
|
|
120
120
|
collectText: typeof collectText;
|
|
121
121
|
knownNamesOf: typeof knownNamesOf;
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
handleSuggest: typeof handleSuggest;
|
|
123
|
+
registerSuggestRoute: typeof registerSuggestRoute;
|
|
124
124
|
routeOf: typeof routeOf;
|
|
125
125
|
quietEffortFor: typeof quietEffortFor;
|
|
126
126
|
listModels: typeof listModels;
|
package/lib/index.js
CHANGED
|
@@ -90,14 +90,14 @@ function splitRoute(model) {
|
|
|
90
90
|
}
|
|
91
91
|
//#endregion
|
|
92
92
|
//#region src/shared/route.ts
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
const
|
|
93
|
+
const SUGGEST_ROUTE = "/api/desktop-enhance/suggest";
|
|
94
|
+
const SUGGEST_MODELS_ROUTE = "/api/desktop-enhance/suggest-models";
|
|
95
|
+
const SUGGEST_EFFORTS_ROUTE = "/api/desktop-enhance/suggest-efforts";
|
|
96
96
|
//#endregion
|
|
97
|
-
//#region src/
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
const
|
|
97
|
+
//#region src/suggest/host.ts
|
|
98
|
+
const SUGGEST_PATH = SUGGEST_ROUTE;
|
|
99
|
+
const SUGGEST_MODELS_PATH = SUGGEST_MODELS_ROUTE;
|
|
100
|
+
const SUGGEST_EFFORTS_PATH = SUGGEST_EFFORTS_ROUTE;
|
|
101
101
|
const MODEL_TIMEOUT_MS = 2e4;
|
|
102
102
|
const MAX_OUTPUT_TOKENS = 4e3;
|
|
103
103
|
function fetchRegistryOf(ctx) {
|
|
@@ -116,9 +116,9 @@ async function collectText(chunks) {
|
|
|
116
116
|
}
|
|
117
117
|
if (chunk.type === "finish") finish = chunk.reason ?? {};
|
|
118
118
|
}
|
|
119
|
-
if (finish === null) throw new Error("
|
|
119
|
+
if (finish === null) throw new Error("suggest: the model stream ended without a finish chunk");
|
|
120
120
|
const kind = finish.kind;
|
|
121
|
-
if (kind !== "stop" && kind !== "max-tokens") throw new Error(`
|
|
121
|
+
if (kind !== "stop" && kind !== "max-tokens") throw new Error(`suggest: the model call did not finish normally (${String(kind)})`);
|
|
122
122
|
return [...parts.entries()].sort((left, right) => left[0] - right[0]).map(([, value]) => value).join("");
|
|
123
123
|
}
|
|
124
124
|
function routeOf(session) {
|
|
@@ -155,7 +155,7 @@ function knownNamesOf(messages) {
|
|
|
155
155
|
}
|
|
156
156
|
return found ? names : null;
|
|
157
157
|
}
|
|
158
|
-
async function
|
|
158
|
+
async function handleSuggest(ctx, request, timeoutMs = MODEL_TIMEOUT_MS) {
|
|
159
159
|
const empty = () => json({ items: [] });
|
|
160
160
|
let sessionId;
|
|
161
161
|
let preference = FOLLOW_SESSION;
|
|
@@ -235,7 +235,7 @@ function withDiag(ctx, body, record) {
|
|
|
235
235
|
});
|
|
236
236
|
}
|
|
237
237
|
function logDiag(ctx, record) {
|
|
238
|
-
const text = `
|
|
238
|
+
const text = `suggest: ${JSON.stringify(record)}`;
|
|
239
239
|
ctx.logger?.warn(text);
|
|
240
240
|
}
|
|
241
241
|
async function quietEffortFor(llm, route) {
|
|
@@ -307,25 +307,25 @@ function json(body, status = 200) {
|
|
|
307
307
|
headers: { "content-type": "application/json" }
|
|
308
308
|
});
|
|
309
309
|
}
|
|
310
|
-
function
|
|
310
|
+
function registerSuggestRoute(ctx) {
|
|
311
311
|
const registry = fetchRegistryOf(ctx);
|
|
312
312
|
if (registry === null) return () => {};
|
|
313
313
|
const disposers = [];
|
|
314
314
|
disposers.push(registry.register({
|
|
315
|
-
path:
|
|
315
|
+
path: SUGGEST_PATH,
|
|
316
316
|
methods: ["POST"],
|
|
317
317
|
requestBody: "buffered",
|
|
318
|
-
fetch: (request) =>
|
|
318
|
+
fetch: (request) => handleSuggest(ctx, request)
|
|
319
319
|
}));
|
|
320
320
|
try {
|
|
321
321
|
disposers.push(registry.register({
|
|
322
|
-
path:
|
|
322
|
+
path: SUGGEST_MODELS_PATH,
|
|
323
323
|
methods: ["GET"],
|
|
324
324
|
requestBody: "buffered",
|
|
325
325
|
fetch: async () => json(await listModels(ctx))
|
|
326
326
|
}));
|
|
327
327
|
disposers.push(registry.register({
|
|
328
|
-
path:
|
|
328
|
+
path: SUGGEST_EFFORTS_PATH,
|
|
329
329
|
methods: ["GET"],
|
|
330
330
|
requestBody: "buffered",
|
|
331
331
|
fetch: async (request) => {
|
|
@@ -350,32 +350,32 @@ const Config = Schema.object({
|
|
|
350
350
|
findBar: Schema.boolean().default(true).volatile(),
|
|
351
351
|
turnPrefix: Schema.boolean().default(true).volatile(),
|
|
352
352
|
compactionRow: Schema.boolean().default(true).volatile(),
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
353
|
+
suggest: Schema.boolean().default(true).volatile(),
|
|
354
|
+
suggestModel: Schema.string().default("").volatile(),
|
|
355
|
+
suggestReasoning: Schema.string().default("").volatile(),
|
|
356
|
+
suggestPrompt: Schema.string().default("").volatile()
|
|
357
357
|
});
|
|
358
358
|
function apply(ctx) {
|
|
359
359
|
ctx.inject(["connection"], (serviceCtx) => {
|
|
360
360
|
try {
|
|
361
|
-
serviceCtx.effect(() =>
|
|
361
|
+
serviceCtx.effect(() => registerSuggestRoute(serviceCtx), "desktop-enhance: suggest route");
|
|
362
362
|
} catch (error) {
|
|
363
|
-
serviceCtx.logger?.warn(`desktop-enhance:
|
|
363
|
+
serviceCtx.logger?.warn(`desktop-enhance: suggest route not registered: ${String(error)}`);
|
|
364
364
|
}
|
|
365
365
|
});
|
|
366
366
|
}
|
|
367
367
|
const __test = {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
368
|
+
SUGGEST_PATH,
|
|
369
|
+
SUGGEST_MODELS_PATH,
|
|
370
|
+
SUGGEST_EFFORTS_PATH,
|
|
371
371
|
MODEL_TIMEOUT_MS,
|
|
372
372
|
MAX_OUTPUT_TOKENS,
|
|
373
373
|
buildPrompt,
|
|
374
374
|
buildMessages,
|
|
375
375
|
collectText,
|
|
376
376
|
knownNamesOf,
|
|
377
|
-
|
|
378
|
-
|
|
377
|
+
handleSuggest,
|
|
378
|
+
registerSuggestRoute,
|
|
379
379
|
routeOf,
|
|
380
380
|
quietEffortFor,
|
|
381
381
|
listModels,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-desktop-enhance",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "DSH Desktop 界面增强:页内查找(Cmd+F
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "DSH Desktop 界面增强:页内查找(Cmd+F)、轮次编号、上下文压缩行常显、建议。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./lib/index.js",
|
|
@@ -26,18 +26,6 @@
|
|
|
26
26
|
"lib",
|
|
27
27
|
"cordis.patch.yml"
|
|
28
28
|
],
|
|
29
|
-
"scripts": {
|
|
30
|
-
"build": "tsdown",
|
|
31
|
-
"dev": "tsdown --watch",
|
|
32
|
-
"typecheck": "tsc --noEmit",
|
|
33
|
-
"test": "node --test tests/*.test.mjs",
|
|
34
|
-
"test:isolation": "./tools/test-isolation.sh",
|
|
35
|
-
"verify": "pnpm typecheck && pnpm build && pnpm test && pnpm test:isolation",
|
|
36
|
-
"prepack": "pnpm build",
|
|
37
|
-
"prepublishOnly": "pnpm verify",
|
|
38
|
-
"release:patch": "npm version patch && pnpm publish",
|
|
39
|
-
"release:minor": "npm version minor && pnpm publish"
|
|
40
|
-
},
|
|
41
29
|
"publishConfig": {
|
|
42
30
|
"access": "public"
|
|
43
31
|
},
|
|
@@ -55,5 +43,15 @@
|
|
|
55
43
|
"@types/react": "^18.3.31",
|
|
56
44
|
"tsdown": "0.23.0",
|
|
57
45
|
"typescript": "5.9.3"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsdown",
|
|
49
|
+
"dev": "tsdown --watch",
|
|
50
|
+
"typecheck": "tsc --noEmit",
|
|
51
|
+
"test": "node --test tests/*.test.mjs",
|
|
52
|
+
"test:isolation": "./tools/test-isolation.sh",
|
|
53
|
+
"verify": "pnpm typecheck && pnpm build && pnpm test && pnpm test:isolation",
|
|
54
|
+
"release:patch": "npm version patch && pnpm publish",
|
|
55
|
+
"release:minor": "npm version minor && pnpm publish"
|
|
58
56
|
}
|
|
59
|
-
}
|
|
57
|
+
}
|