@qzsy/dsh-bridge 3.4.4 → 3.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/README.md +1 -0
- package/client/client.js +164 -8
- package/client/mobile.js +164 -8
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# 更新日志
|
|
2
2
|
|
|
3
|
+
## [v3.5.1] - 2026-11-02
|
|
4
|
+
|
|
5
|
+
### 🐛 修复
|
|
6
|
+
|
|
7
|
+
- **选当前模型也能继续**:选中项与当前模型相同时,宿主不一定会关闭模型菜单;现在会先按 Esc / 外部点击收起旧菜单,再打开父级并进入「推理等级」,不会卡在半路。
|
|
8
|
+
- **父菜单点击时序**:等父 popover 进入动画和事件绑定完成后再点「推理等级」,避免点得太早导致推理 sheet 不出现。
|
|
9
|
+
- **过渡期宿主菜单改为透明隐藏**:不再用 `visibility:hidden`,避免宿主按钮虽然可见性隐藏却无法被程序化点击;推理 sheet 出现后立即恢复。
|
|
10
|
+
|
|
11
|
+
### 🧪 验证
|
|
12
|
+
|
|
13
|
+
- 独立宿主模拟:模型 sheet → 选模型 → 推理 sheet → 选等级关闭,4/4;待安装后跑真实 DSH。
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## [v3.5.0] - 2026-11-02
|
|
17
|
+
|
|
18
|
+
### ✨ 新增
|
|
19
|
+
|
|
20
|
+
- **模型 → 思考级别连招**:在模型 sheet 里选中任意模型后,不再直接关闭整个菜单,而是自动重新打开设置菜单并进入「推理等级」子菜单,以同一个底部 sheet 呈现 Off / Low / High / Max,选完才关闭。
|
|
21
|
+
- **无闪跳过渡**:选中模型时先把旧 sheet 快照留在原地,宿主菜单在背后切换,推理 sheet 滑入后再移除快照;中间宿主菜单隐藏,不会闪出桌面 popover。
|
|
22
|
+
- 模型选中、推理等级选中仍由宿主完成,插件只负责串联和 sheet 化;桌面端不变。
|
|
23
|
+
|
|
24
|
+
### 🧪 验证
|
|
25
|
+
|
|
26
|
+
- 独立宿主模拟:模型 sheet → 选模型 → 自动进入推理 sheet(Off/Low/High/Max)→ 选等级关闭并清理,4/4 通过。
|
|
27
|
+
- 运行中的 DSH:待 3.5.0 安装后验证完整链路。
|
|
28
|
+
|
|
29
|
+
|
|
3
30
|
## [v3.4.4] - 2026-11-02
|
|
4
31
|
|
|
5
32
|
### 🐛 修复
|
package/README.md
CHANGED
|
@@ -49,6 +49,7 @@ dsh plugin --profile <name> add @qzsy/dsh-bridge
|
|
|
49
49
|
- 内容区占满屏宽,左上角「菜单」按钮打开会话 / 工作区 / 插件入口;
|
|
50
50
|
- 支持手势:左缘向右滑打开、抽屉内向左滑关闭,拖动时跟手,松手吸附;
|
|
51
51
|
- 模型切换器在手机上改为底部 sheet:全宽、抓手、遮罩,支持下拉/点遮罩关闭;默认不弹键盘(搜索框 `readonly`),需要搜索时再点;
|
|
52
|
+
- 选完模型自动继续进入「推理等级」sheet,Off / Low / High / Max 选完才关闭,手机上和桌面菜单一样连贯;
|
|
52
53
|
- 全面屏自动避开安全区:刘海 / 状态栏 / 底部 home indicator 不遮挡内容;
|
|
53
54
|
- 点遮罩、点会话行、按 Esc 或转回桌面宽度都会自动收起;
|
|
54
55
|
- 桌面端保持 DSH 原生布局,不受影响。
|
package/client/client.js
CHANGED
|
@@ -463,6 +463,15 @@ var MOBILE_DRAWER_CSS = `
|
|
|
463
463
|
transition: transform 220ms ease, opacity 220ms ease !important;
|
|
464
464
|
animation: none !important;
|
|
465
465
|
}
|
|
466
|
+
/* \u9009\u4E2D\u6A21\u578B\u540E\u8FDB\u5165\u300C\u63A8\u7406\u7B49\u7EA7\u300D\u7684\u8FC7\u6E21\uFF1A\u65E7 sheet \u7684\u5FEB\u7167\u7559\u5728\u539F\u5730\uFF0C\u5BBF\u4E3B\u83DC\u5355\u5148\u9690\u85CF */
|
|
467
|
+
[data-qzsy-model-sheet-clone] {
|
|
468
|
+
z-index: 1199 !important;
|
|
469
|
+
pointer-events: none !important;
|
|
470
|
+
}
|
|
471
|
+
body.qzsy-model-advancing div[id$="-menu"]:not([data-qzsy-model-sheet]):not([data-qzsy-model-sheet-clone]) {
|
|
472
|
+
opacity: 0 !important;
|
|
473
|
+
pointer-events: none !important;
|
|
474
|
+
}
|
|
466
475
|
body.qzsy-model-sheet-dragging [data-qzsy-model-sheet] {
|
|
467
476
|
transform: translateY(var(--qzsy-model-sheet-y, 0px)) !important;
|
|
468
477
|
transition: none !important;
|
|
@@ -516,6 +525,10 @@ function setupMobileDrawer() {
|
|
|
516
525
|
let modelChainUntil = 0;
|
|
517
526
|
let modelDrag = null;
|
|
518
527
|
let modelDragHandlers = null;
|
|
528
|
+
let modelClone = null;
|
|
529
|
+
let modelAdvancing = false;
|
|
530
|
+
let reasoningStep = false;
|
|
531
|
+
let modelAdvanceToken = 0;
|
|
519
532
|
const preventDrawerScroll = (event) => {
|
|
520
533
|
if (!gesture || !event.cancelable) return;
|
|
521
534
|
const touch = event.touches?.[0];
|
|
@@ -633,7 +646,7 @@ function setupMobileDrawer() {
|
|
|
633
646
|
if (search) {
|
|
634
647
|
const menu = search.closest('[role="menu"]') || search.closest('[class*="_menu"]');
|
|
635
648
|
const portal = bodyPortalOf(menu || search);
|
|
636
|
-
if (portal && visiblePortal(portal)) {
|
|
649
|
+
if (portal && visiblePortal(portal) && !portal.hasAttribute("data-qzsy-model-sheet-clone")) {
|
|
637
650
|
const s = getComputedStyle(portal);
|
|
638
651
|
if ((s.position === "fixed" || s.position === "absolute") && portal.getBoundingClientRect().width > 120) return portal;
|
|
639
652
|
}
|
|
@@ -641,7 +654,8 @@ function setupMobileDrawer() {
|
|
|
641
654
|
const candidates = [];
|
|
642
655
|
for (const el of document.body.children) {
|
|
643
656
|
if (!(el instanceof HTMLElement)) continue;
|
|
644
|
-
if (el === modelBackdrop || el.classList.contains(HEADER_CLASS) || el.classList.contains(BACKDROP_CLASS)) continue;
|
|
657
|
+
if (el === modelBackdrop || el === modelClone || el.classList.contains(HEADER_CLASS) || el.classList.contains(BACKDROP_CLASS)) continue;
|
|
658
|
+
if (el.hasAttribute("data-qzsy-model-sheet-clone")) continue;
|
|
645
659
|
if (!visiblePortal(el)) continue;
|
|
646
660
|
const s = getComputedStyle(el);
|
|
647
661
|
if (s.position !== "fixed" && s.position !== "absolute") continue;
|
|
@@ -661,6 +675,26 @@ function setupMobileDrawer() {
|
|
|
661
675
|
candidates.sort((a, b) => Number(b.hasSearch) - Number(a.hasSearch) || Number(b.hasModelMarker) - Number(a.hasModelMarker) || b.rows - a.rows);
|
|
662
676
|
return candidates[0]?.el || null;
|
|
663
677
|
};
|
|
678
|
+
const findReasoningPortal = () => {
|
|
679
|
+
if (!isMobileViewport()) return null;
|
|
680
|
+
const candidates = [];
|
|
681
|
+
for (const el of document.body.children) {
|
|
682
|
+
if (!(el instanceof HTMLElement)) continue;
|
|
683
|
+
if (el === modelBackdrop || el === modelClone || el.classList.contains(HEADER_CLASS) || el.classList.contains(BACKDROP_CLASS)) continue;
|
|
684
|
+
if (el.hasAttribute("data-qzsy-model-sheet") || el.hasAttribute("data-qzsy-model-sheet-clone")) continue;
|
|
685
|
+
if (!visiblePortal(el)) continue;
|
|
686
|
+
const s = getComputedStyle(el);
|
|
687
|
+
if (s.position !== "fixed" && s.position !== "absolute") continue;
|
|
688
|
+
const menu = el.querySelector('[role="menu"]');
|
|
689
|
+
if (!menu) continue;
|
|
690
|
+
const radios = menu.querySelectorAll('button[role="menuitemradio"], [role="menuitemradio"], input[type="radio"]').length;
|
|
691
|
+
if (radios < 1) continue;
|
|
692
|
+
const text = menu.innerText || "";
|
|
693
|
+
if (/搜索模型|Search model|DeepSeek|claude|模型与推理等级/i.test(text)) continue;
|
|
694
|
+
candidates.push(el);
|
|
695
|
+
}
|
|
696
|
+
return candidates[candidates.length - 1] || null;
|
|
697
|
+
};
|
|
664
698
|
const hostBackdropPresent = () => {
|
|
665
699
|
for (const el of document.body.children) {
|
|
666
700
|
if (!(el instanceof HTMLElement)) continue;
|
|
@@ -700,7 +734,23 @@ function setupMobileDrawer() {
|
|
|
700
734
|
}, 450);
|
|
701
735
|
}, 120);
|
|
702
736
|
};
|
|
737
|
+
const dismissHostMenus = () => {
|
|
738
|
+
try {
|
|
739
|
+
document.body.dispatchEvent(new PointerEvent("pointerdown", { bubbles: true, cancelable: true }));
|
|
740
|
+
} catch {
|
|
741
|
+
}
|
|
742
|
+
try {
|
|
743
|
+
document.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", bubbles: true, cancelable: true }));
|
|
744
|
+
} catch {
|
|
745
|
+
}
|
|
746
|
+
};
|
|
703
747
|
const closeModelSheetNow = () => {
|
|
748
|
+
if (modelAdvancing) {
|
|
749
|
+
cancelAdvanceOverlay();
|
|
750
|
+
clearModelSheet();
|
|
751
|
+
dismissHostMenus();
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
704
754
|
const portal = modelPortal;
|
|
705
755
|
if (!portal) return;
|
|
706
756
|
document.body.classList.remove("qzsy-model-sheet-open");
|
|
@@ -709,6 +759,10 @@ function setupMobileDrawer() {
|
|
|
709
759
|
requestHostModelClose(portal);
|
|
710
760
|
};
|
|
711
761
|
const closeModelSheetAnimated = () => {
|
|
762
|
+
if (modelAdvancing) {
|
|
763
|
+
closeModelSheetNow();
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
712
766
|
const portal = modelPortal;
|
|
713
767
|
if (!portal) return;
|
|
714
768
|
portal.classList.add("qzsy-model-sheet-closing");
|
|
@@ -778,28 +832,42 @@ function setupMobileDrawer() {
|
|
|
778
832
|
portal.addEventListener("touchcancel", onEnd, { passive: true });
|
|
779
833
|
modelDragHandlers = { onStart, onMove, onEnd };
|
|
780
834
|
};
|
|
781
|
-
const clearModelSheet = () => {
|
|
835
|
+
const clearModelSheet = ({ keepChrome = false } = {}) => {
|
|
782
836
|
if (modelPortal) {
|
|
783
837
|
detachModelDrag();
|
|
784
838
|
modelPortal.removeAttribute("data-qzsy-model-sheet");
|
|
839
|
+
modelPortal.removeAttribute("data-qzsy-model-step");
|
|
785
840
|
modelPortal.classList.remove("qzsy-model-sheet", "qzsy-model-sheet-closing");
|
|
786
841
|
}
|
|
787
842
|
modelPortal = null;
|
|
788
843
|
modelDrag = null;
|
|
789
|
-
|
|
844
|
+
modelAdvanceToken += 1;
|
|
845
|
+
modelAdvancing = false;
|
|
846
|
+
reasoningStep = false;
|
|
847
|
+
if (modelClone) {
|
|
848
|
+
modelClone.remove();
|
|
849
|
+
modelClone = null;
|
|
850
|
+
}
|
|
851
|
+
document.body?.classList.remove("qzsy-model-advancing", "qzsy-model-sheet-dragging");
|
|
790
852
|
document.body?.style.removeProperty("--qzsy-model-sheet-y");
|
|
791
853
|
document.body?.style.removeProperty("--qzsy-model-sheet-progress");
|
|
792
|
-
if (
|
|
793
|
-
|
|
794
|
-
modelBackdrop
|
|
854
|
+
if (!keepChrome) {
|
|
855
|
+
document.body?.classList.remove("qzsy-model-sheet-open");
|
|
856
|
+
if (modelBackdrop) {
|
|
857
|
+
modelBackdrop.remove();
|
|
858
|
+
modelBackdrop = null;
|
|
859
|
+
}
|
|
795
860
|
}
|
|
796
861
|
};
|
|
797
862
|
const applyModelSheet = (portal) => {
|
|
798
863
|
if (modelPortal === portal) return;
|
|
799
|
-
|
|
864
|
+
const step = reasoningStep ? "reasoning" : "model";
|
|
865
|
+
const keepChrome = modelAdvancing && Boolean(modelClone);
|
|
866
|
+
clearModelSheet({ keepChrome });
|
|
800
867
|
modelPortal = portal;
|
|
801
868
|
modelChainUntil = 0;
|
|
802
869
|
portal.setAttribute("data-qzsy-model-sheet", "");
|
|
870
|
+
portal.setAttribute("data-qzsy-model-step", step);
|
|
803
871
|
portal.classList.add("qzsy-model-sheet");
|
|
804
872
|
attachModelDrag(portal);
|
|
805
873
|
ensureModelBackdrop();
|
|
@@ -838,12 +906,96 @@ function setupMobileDrawer() {
|
|
|
838
906
|
if (!disposed && modelPortal === portal) document.body.classList.add("qzsy-model-sheet-open");
|
|
839
907
|
});
|
|
840
908
|
};
|
|
909
|
+
const cancelAdvanceOverlay = () => {
|
|
910
|
+
modelAdvanceToken += 1;
|
|
911
|
+
modelAdvancing = false;
|
|
912
|
+
reasoningStep = false;
|
|
913
|
+
document.body?.classList.remove("qzsy-model-advancing");
|
|
914
|
+
if (modelClone) {
|
|
915
|
+
modelClone.remove();
|
|
916
|
+
modelClone = null;
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
const beginReasoningAdvance = (portal) => {
|
|
920
|
+
if (disposed || modelAdvancing) return;
|
|
921
|
+
if (portal.getAttribute("data-qzsy-model-step") !== "model") return;
|
|
922
|
+
if (!portal.querySelector('button[role="menuitemradio"], [role="menuitemradio"]')) return;
|
|
923
|
+
modelAdvancing = true;
|
|
924
|
+
const token = ++modelAdvanceToken;
|
|
925
|
+
document.body.classList.add("qzsy-model-advancing");
|
|
926
|
+
modelClone = portal.cloneNode(true);
|
|
927
|
+
modelClone.setAttribute("data-qzsy-model-sheet-clone", "");
|
|
928
|
+
modelClone.setAttribute("aria-hidden", "true");
|
|
929
|
+
for (const el of modelClone.querySelectorAll("[id]")) el.removeAttribute("id");
|
|
930
|
+
document.body.appendChild(modelClone);
|
|
931
|
+
window.setTimeout(() => {
|
|
932
|
+
if (disposed || token !== modelAdvanceToken || !modelAdvancing) return;
|
|
933
|
+
if (modelPortal && visiblePortal(modelPortal)) {
|
|
934
|
+
try {
|
|
935
|
+
dismissHostMenus();
|
|
936
|
+
} catch {
|
|
937
|
+
}
|
|
938
|
+
window.setTimeout(() => openParentAndReason(), 100);
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
openParentAndReason();
|
|
942
|
+
function openParentAndReason() {
|
|
943
|
+
if (disposed || token !== modelAdvanceToken || !modelAdvancing) return;
|
|
944
|
+
const trigger = document.querySelector(
|
|
945
|
+
'button[aria-haspopup="menu"][aria-label*="\u9009\u62E9\u6A21\u578B"], button[aria-haspopup="menu"][aria-label*="Select model"], button[aria-haspopup="menu"][aria-label*="\u6A21\u578B"]'
|
|
946
|
+
);
|
|
947
|
+
try {
|
|
948
|
+
trigger?.click();
|
|
949
|
+
} catch {
|
|
950
|
+
}
|
|
951
|
+
let attempts = 0;
|
|
952
|
+
const openReasonCell = () => {
|
|
953
|
+
if (disposed || token !== modelAdvanceToken || !modelAdvancing) return;
|
|
954
|
+
const cell = [...document.querySelectorAll('button[role="menuitem"]')].find((b) => /推理等级|Reasoning effort|Reasoning level|推理强度/i.test(b.innerText || ""));
|
|
955
|
+
if (cell) {
|
|
956
|
+
reasoningStep = true;
|
|
957
|
+
try {
|
|
958
|
+
cell.click();
|
|
959
|
+
} catch {
|
|
960
|
+
}
|
|
961
|
+
window.setTimeout(() => {
|
|
962
|
+
if (disposed || token !== modelAdvanceToken) return;
|
|
963
|
+
if (!modelPortal) {
|
|
964
|
+
cancelAdvanceOverlay();
|
|
965
|
+
clearModelSheet();
|
|
966
|
+
}
|
|
967
|
+
}, 1200);
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
attempts += 1;
|
|
971
|
+
if (attempts > 20) {
|
|
972
|
+
cancelAdvanceOverlay();
|
|
973
|
+
clearModelSheet();
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
window.setTimeout(openReasonCell, 60);
|
|
977
|
+
};
|
|
978
|
+
window.setTimeout(openReasonCell, 300);
|
|
979
|
+
}
|
|
980
|
+
}, 140);
|
|
981
|
+
};
|
|
841
982
|
const syncModelSheet = () => {
|
|
842
983
|
if (disposed) return;
|
|
843
984
|
if (!isMobileViewport()) {
|
|
844
985
|
clearModelSheet();
|
|
845
986
|
return;
|
|
846
987
|
}
|
|
988
|
+
if (modelAdvancing) {
|
|
989
|
+
if (reasoningStep) {
|
|
990
|
+
const next = findReasoningPortal();
|
|
991
|
+
if (next) {
|
|
992
|
+
applyModelSheet(next);
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
if (modelPortal && !visiblePortal(modelPortal)) modelPortal = null;
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
847
999
|
if (modelPortal && !visiblePortal(modelPortal)) clearModelSheet();
|
|
848
1000
|
const found = findModelPortal();
|
|
849
1001
|
if (!found) {
|
|
@@ -872,6 +1024,10 @@ function setupMobileDrawer() {
|
|
|
872
1024
|
window.setTimeout(syncModelSheet, 30);
|
|
873
1025
|
window.setTimeout(syncModelSheet, 180);
|
|
874
1026
|
}
|
|
1027
|
+
const modelOption = target.closest('button[role="menuitemradio"], [role="menuitemradio"]');
|
|
1028
|
+
if (modelOption && modelPortal && modelPortal.getAttribute("data-qzsy-model-step") === "model" && modelPortal.contains(modelOption)) {
|
|
1029
|
+
beginReasoningAdvance(modelPortal);
|
|
1030
|
+
}
|
|
875
1031
|
if (!isOpen()) return;
|
|
876
1032
|
if (target.closest(`.${BACKDROP_CLASS}`)) {
|
|
877
1033
|
closeDrawer();
|
package/client/mobile.js
CHANGED
|
@@ -260,6 +260,15 @@ export const MOBILE_DRAWER_CSS = `
|
|
|
260
260
|
transition: transform 220ms ease, opacity 220ms ease !important;
|
|
261
261
|
animation: none !important;
|
|
262
262
|
}
|
|
263
|
+
/* 选中模型后进入「推理等级」的过渡:旧 sheet 的快照留在原地,宿主菜单先隐藏 */
|
|
264
|
+
[data-qzsy-model-sheet-clone] {
|
|
265
|
+
z-index: 1199 !important;
|
|
266
|
+
pointer-events: none !important;
|
|
267
|
+
}
|
|
268
|
+
body.qzsy-model-advancing div[id$="-menu"]:not([data-qzsy-model-sheet]):not([data-qzsy-model-sheet-clone]) {
|
|
269
|
+
opacity: 0 !important;
|
|
270
|
+
pointer-events: none !important;
|
|
271
|
+
}
|
|
263
272
|
body.qzsy-model-sheet-dragging [data-qzsy-model-sheet] {
|
|
264
273
|
transform: translateY(var(--qzsy-model-sheet-y, 0px)) !important;
|
|
265
274
|
transition: none !important;
|
|
@@ -322,6 +331,10 @@ export function setupMobileDrawer() {
|
|
|
322
331
|
let modelChainUntil = 0;
|
|
323
332
|
let modelDrag = null;
|
|
324
333
|
let modelDragHandlers = null;
|
|
334
|
+
let modelClone = null;
|
|
335
|
+
let modelAdvancing = false;
|
|
336
|
+
let reasoningStep = false;
|
|
337
|
+
let modelAdvanceToken = 0;
|
|
325
338
|
|
|
326
339
|
const preventDrawerScroll = (event) => {
|
|
327
340
|
if (!gesture || !event.cancelable) return;
|
|
@@ -451,7 +464,7 @@ export function setupMobileDrawer() {
|
|
|
451
464
|
if (search) {
|
|
452
465
|
const menu = search.closest('[role="menu"]') || search.closest('[class*="_menu"]');
|
|
453
466
|
const portal = bodyPortalOf(menu || search);
|
|
454
|
-
if (portal && visiblePortal(portal)) {
|
|
467
|
+
if (portal && visiblePortal(portal) && !portal.hasAttribute('data-qzsy-model-sheet-clone')) {
|
|
455
468
|
const s = getComputedStyle(portal);
|
|
456
469
|
if ((s.position === 'fixed' || s.position === 'absolute') && portal.getBoundingClientRect().width > 120) return portal;
|
|
457
470
|
}
|
|
@@ -460,7 +473,8 @@ export function setupMobileDrawer() {
|
|
|
460
473
|
const candidates = [];
|
|
461
474
|
for (const el of document.body.children) {
|
|
462
475
|
if (!(el instanceof HTMLElement)) continue;
|
|
463
|
-
if (el === modelBackdrop || el.classList.contains(HEADER_CLASS) || el.classList.contains(BACKDROP_CLASS)) continue;
|
|
476
|
+
if (el === modelBackdrop || el === modelClone || el.classList.contains(HEADER_CLASS) || el.classList.contains(BACKDROP_CLASS)) continue;
|
|
477
|
+
if (el.hasAttribute('data-qzsy-model-sheet-clone')) continue;
|
|
464
478
|
if (!visiblePortal(el)) continue;
|
|
465
479
|
const s = getComputedStyle(el);
|
|
466
480
|
if (s.position !== 'fixed' && s.position !== 'absolute') continue;
|
|
@@ -485,6 +499,28 @@ export function setupMobileDrawer() {
|
|
|
485
499
|
return candidates[0]?.el || null;
|
|
486
500
|
};
|
|
487
501
|
|
|
502
|
+
const findReasoningPortal = () => {
|
|
503
|
+
if (!isMobileViewport()) return null;
|
|
504
|
+
const candidates = [];
|
|
505
|
+
for (const el of document.body.children) {
|
|
506
|
+
if (!(el instanceof HTMLElement)) continue;
|
|
507
|
+
if (el === modelBackdrop || el === modelClone || el.classList.contains(HEADER_CLASS) || el.classList.contains(BACKDROP_CLASS)) continue;
|
|
508
|
+
if (el.hasAttribute('data-qzsy-model-sheet') || el.hasAttribute('data-qzsy-model-sheet-clone')) continue;
|
|
509
|
+
if (!visiblePortal(el)) continue;
|
|
510
|
+
const s = getComputedStyle(el);
|
|
511
|
+
if (s.position !== 'fixed' && s.position !== 'absolute') continue;
|
|
512
|
+
const menu = el.querySelector('[role="menu"]');
|
|
513
|
+
if (!menu) continue;
|
|
514
|
+
const radios = menu.querySelectorAll('button[role="menuitemradio"], [role="menuitemradio"], input[type="radio"]').length;
|
|
515
|
+
if (radios < 1) continue;
|
|
516
|
+
const text = menu.innerText || '';
|
|
517
|
+
// 推理等级菜单只含 Off / Low / High / Max 等档位,不含模型搜索与模型分组
|
|
518
|
+
if (/搜索模型|Search model|DeepSeek|claude|模型与推理等级/i.test(text)) continue;
|
|
519
|
+
candidates.push(el);
|
|
520
|
+
}
|
|
521
|
+
return candidates[candidates.length - 1] || null;
|
|
522
|
+
};
|
|
523
|
+
|
|
488
524
|
const hostBackdropPresent = () => {
|
|
489
525
|
for (const el of document.body.children) {
|
|
490
526
|
if (!(el instanceof HTMLElement)) continue;
|
|
@@ -517,7 +553,18 @@ export function setupMobileDrawer() {
|
|
|
517
553
|
}, 120);
|
|
518
554
|
};
|
|
519
555
|
|
|
556
|
+
const dismissHostMenus = () => {
|
|
557
|
+
try { document.body.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true, cancelable: true })); } catch { /* 忽略 */ }
|
|
558
|
+
try { document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true })); } catch { /* 忽略 */ }
|
|
559
|
+
};
|
|
560
|
+
|
|
520
561
|
const closeModelSheetNow = () => {
|
|
562
|
+
if (modelAdvancing) {
|
|
563
|
+
cancelAdvanceOverlay();
|
|
564
|
+
clearModelSheet();
|
|
565
|
+
dismissHostMenus();
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
521
568
|
const portal = modelPortal;
|
|
522
569
|
if (!portal) return;
|
|
523
570
|
document.body.classList.remove('qzsy-model-sheet-open');
|
|
@@ -527,6 +574,10 @@ export function setupMobileDrawer() {
|
|
|
527
574
|
};
|
|
528
575
|
|
|
529
576
|
const closeModelSheetAnimated = () => {
|
|
577
|
+
if (modelAdvancing) {
|
|
578
|
+
closeModelSheetNow();
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
530
581
|
const portal = modelPortal;
|
|
531
582
|
if (!portal) return;
|
|
532
583
|
portal.classList.add('qzsy-model-sheet-closing');
|
|
@@ -600,29 +651,43 @@ export function setupMobileDrawer() {
|
|
|
600
651
|
modelDragHandlers = { onStart, onMove, onEnd };
|
|
601
652
|
};
|
|
602
653
|
|
|
603
|
-
const clearModelSheet = () => {
|
|
654
|
+
const clearModelSheet = ({ keepChrome = false } = {}) => {
|
|
604
655
|
if (modelPortal) {
|
|
605
656
|
detachModelDrag();
|
|
606
657
|
modelPortal.removeAttribute('data-qzsy-model-sheet');
|
|
658
|
+
modelPortal.removeAttribute('data-qzsy-model-step');
|
|
607
659
|
modelPortal.classList.remove('qzsy-model-sheet', 'qzsy-model-sheet-closing');
|
|
608
660
|
}
|
|
609
661
|
modelPortal = null;
|
|
610
662
|
modelDrag = null;
|
|
611
|
-
|
|
663
|
+
modelAdvanceToken += 1;
|
|
664
|
+
modelAdvancing = false;
|
|
665
|
+
reasoningStep = false;
|
|
666
|
+
if (modelClone) {
|
|
667
|
+
modelClone.remove();
|
|
668
|
+
modelClone = null;
|
|
669
|
+
}
|
|
670
|
+
document.body?.classList.remove('qzsy-model-advancing', 'qzsy-model-sheet-dragging');
|
|
612
671
|
document.body?.style.removeProperty('--qzsy-model-sheet-y');
|
|
613
672
|
document.body?.style.removeProperty('--qzsy-model-sheet-progress');
|
|
614
|
-
if (
|
|
615
|
-
|
|
616
|
-
modelBackdrop
|
|
673
|
+
if (!keepChrome) {
|
|
674
|
+
document.body?.classList.remove('qzsy-model-sheet-open');
|
|
675
|
+
if (modelBackdrop) {
|
|
676
|
+
modelBackdrop.remove();
|
|
677
|
+
modelBackdrop = null;
|
|
678
|
+
}
|
|
617
679
|
}
|
|
618
680
|
};
|
|
619
681
|
|
|
620
682
|
const applyModelSheet = (portal) => {
|
|
621
683
|
if (modelPortal === portal) return;
|
|
622
|
-
|
|
684
|
+
const step = reasoningStep ? 'reasoning' : 'model';
|
|
685
|
+
const keepChrome = modelAdvancing && Boolean(modelClone);
|
|
686
|
+
clearModelSheet({ keepChrome });
|
|
623
687
|
modelPortal = portal;
|
|
624
688
|
modelChainUntil = 0;
|
|
625
689
|
portal.setAttribute('data-qzsy-model-sheet', '');
|
|
690
|
+
portal.setAttribute('data-qzsy-model-step', step);
|
|
626
691
|
portal.classList.add('qzsy-model-sheet');
|
|
627
692
|
attachModelDrag(portal);
|
|
628
693
|
ensureModelBackdrop();
|
|
@@ -664,12 +729,95 @@ export function setupMobileDrawer() {
|
|
|
664
729
|
});
|
|
665
730
|
};
|
|
666
731
|
|
|
732
|
+
const cancelAdvanceOverlay = () => {
|
|
733
|
+
modelAdvanceToken += 1;
|
|
734
|
+
modelAdvancing = false;
|
|
735
|
+
reasoningStep = false;
|
|
736
|
+
document.body?.classList.remove('qzsy-model-advancing');
|
|
737
|
+
if (modelClone) {
|
|
738
|
+
modelClone.remove();
|
|
739
|
+
modelClone = null;
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
// 选完模型后自动进入推理等级:保留旧 sheet 快照,宿主菜单在背后切换,再滑入推理 sheet
|
|
744
|
+
const beginReasoningAdvance = (portal) => {
|
|
745
|
+
if (disposed || modelAdvancing) return;
|
|
746
|
+
if (portal.getAttribute('data-qzsy-model-step') !== 'model') return;
|
|
747
|
+
if (!portal.querySelector('button[role="menuitemradio"], [role="menuitemradio"]')) return;
|
|
748
|
+
modelAdvancing = true;
|
|
749
|
+
const token = ++modelAdvanceToken;
|
|
750
|
+
document.body.classList.add('qzsy-model-advancing');
|
|
751
|
+
modelClone = portal.cloneNode(true);
|
|
752
|
+
modelClone.setAttribute('data-qzsy-model-sheet-clone', '');
|
|
753
|
+
modelClone.setAttribute('aria-hidden', 'true');
|
|
754
|
+
for (const el of modelClone.querySelectorAll('[id]')) el.removeAttribute('id');
|
|
755
|
+
document.body.appendChild(modelClone);
|
|
756
|
+
|
|
757
|
+
window.setTimeout(() => {
|
|
758
|
+
if (disposed || token !== modelAdvanceToken || !modelAdvancing) return;
|
|
759
|
+
// 选中的是当前模型时宿主可能不关菜单,先按 Esc/外部点击收掉
|
|
760
|
+
if (modelPortal && visiblePortal(modelPortal)) {
|
|
761
|
+
try { dismissHostMenus(); } catch { /* 忽略 */ }
|
|
762
|
+
window.setTimeout(() => openParentAndReason(), 100);
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
openParentAndReason();
|
|
766
|
+
|
|
767
|
+
function openParentAndReason() {
|
|
768
|
+
if (disposed || token !== modelAdvanceToken || !modelAdvancing) return;
|
|
769
|
+
const trigger = document.querySelector(
|
|
770
|
+
'button[aria-haspopup="menu"][aria-label*="选择模型"], button[aria-haspopup="menu"][aria-label*="Select model"], button[aria-haspopup="menu"][aria-label*="模型"]',
|
|
771
|
+
);
|
|
772
|
+
try { trigger?.click(); } catch { /* 忽略 */ }
|
|
773
|
+
let attempts = 0;
|
|
774
|
+
const openReasonCell = () => {
|
|
775
|
+
if (disposed || token !== modelAdvanceToken || !modelAdvancing) return;
|
|
776
|
+
const cell = [...document.querySelectorAll('button[role="menuitem"]')].find((b) => /推理等级|Reasoning effort|Reasoning level|推理强度/i.test(b.innerText || ''));
|
|
777
|
+
if (cell) {
|
|
778
|
+
reasoningStep = true;
|
|
779
|
+
try { cell.click(); } catch { /* 忽略 */ }
|
|
780
|
+
window.setTimeout(() => {
|
|
781
|
+
if (disposed || token !== modelAdvanceToken) return;
|
|
782
|
+
if (!modelPortal) {
|
|
783
|
+
// 推理菜单没出现:撤掉 overlay,避免卡在半路
|
|
784
|
+
cancelAdvanceOverlay();
|
|
785
|
+
clearModelSheet();
|
|
786
|
+
}
|
|
787
|
+
}, 1200);
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
attempts += 1;
|
|
791
|
+
if (attempts > 20) {
|
|
792
|
+
cancelAdvanceOverlay();
|
|
793
|
+
clearModelSheet();
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
window.setTimeout(openReasonCell, 60);
|
|
797
|
+
};
|
|
798
|
+
// 等父菜单的进入动画/事件绑定完成再点「推理等级」
|
|
799
|
+
window.setTimeout(openReasonCell, 300);
|
|
800
|
+
}
|
|
801
|
+
}, 140);
|
|
802
|
+
};
|
|
803
|
+
|
|
667
804
|
const syncModelSheet = () => {
|
|
668
805
|
if (disposed) return;
|
|
669
806
|
if (!isMobileViewport()) {
|
|
670
807
|
clearModelSheet();
|
|
671
808
|
return;
|
|
672
809
|
}
|
|
810
|
+
if (modelAdvancing) {
|
|
811
|
+
if (reasoningStep) {
|
|
812
|
+
const next = findReasoningPortal();
|
|
813
|
+
if (next) {
|
|
814
|
+
applyModelSheet(next);
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
if (modelPortal && !visiblePortal(modelPortal)) modelPortal = null;
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
673
821
|
if (modelPortal && !visiblePortal(modelPortal)) clearModelSheet();
|
|
674
822
|
const found = findModelPortal();
|
|
675
823
|
if (!found) {
|
|
@@ -703,6 +851,14 @@ export function setupMobileDrawer() {
|
|
|
703
851
|
window.setTimeout(syncModelSheet, 180);
|
|
704
852
|
}
|
|
705
853
|
|
|
854
|
+
// 选完模型继续进入推理等级,而不是直接关掉整个菜单
|
|
855
|
+
const modelOption = target.closest('button[role="menuitemradio"], [role="menuitemradio"]');
|
|
856
|
+
if (modelOption && modelPortal
|
|
857
|
+
&& modelPortal.getAttribute('data-qzsy-model-step') === 'model'
|
|
858
|
+
&& modelPortal.contains(modelOption)) {
|
|
859
|
+
beginReasoningAdvance(modelPortal);
|
|
860
|
+
}
|
|
861
|
+
|
|
706
862
|
if (!isOpen()) return;
|
|
707
863
|
|
|
708
864
|
if (target.closest(`.${BACKDROP_CLASS}`)) {
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qzsy/dsh-bridge",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.1",
|
|
4
4
|
"description": "DSH 远程隧道云官方客户端插件:一条命令把本机 DeepSeek Harness 接入云端隧道(设备码绑定、短期令牌、本地门禁代理、HTTP/SSE/WebSocket 反向隧道)。",
|
|
5
|
-
"releaseNotes": "【v3.
|
|
5
|
+
"releaseNotes": "【v3.5.1】模型 → 思考级别连招修复\\n• 选中当前模型时先收起旧菜单,再进入推理等级,不再卡住\\n• 等父菜单动画/事件就绪后再点推理等级,避免 sheet 不出现\\n• 过渡期宿主菜单改透明隐藏,程序化点击可靠",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "lib/index.js",
|
|
8
8
|
"exports": {
|