dsh-composer-ux 0.28.0 → 0.28.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 +23 -0
- package/README.md +19 -1
- package/dsh-plugin.json +1 -1
- package/lib/client.js +34 -7
- package/lib/client.js.map +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
4
4
|
|
|
5
|
+
## [0.28.1] — 2026-10-29(兼容「往这一组里放按钮」的其它插件)
|
|
6
|
+
|
|
7
|
+
用户 2026-10-29(截图圈住侧边栏那一行图标):「如果有其他插件在这里放按钮会怎么样,需要兼容所有往这里放按钮的插件」。
|
|
8
|
+
|
|
9
|
+
**以前会怎样(两个真问题)**
|
|
10
|
+
|
|
11
|
+
1. **收成一条时把整只 `<nav>` 藏了**(`display:none`)—— 别的插件往这一组里塞的按钮会**跟着消失**。
|
|
12
|
+
用户看不到自己的按钮,只会觉得"装了新插件没反应"。
|
|
13
|
+
2. **只留图标时的选择器写的是 `nav > button`** —— 别人用包装层(div 包按钮)注入的节点压缩不到,
|
|
14
|
+
而别人**裸按钮**的文字又会被 `font-size:0` 一起压掉(不是我们该管的东西)。
|
|
15
|
+
|
|
16
|
+
**现在怎么做**
|
|
17
|
+
|
|
18
|
+
- 只处理**认得出的面板行**:`nav` 的直接子节点里,**button + 非空 aria-label + 内含 aria-hidden 图标**。
|
|
19
|
+
宿主自己的 `PanelRow` 与「更多」都长这样;**别的插件通过官方 panel 注册表注册的面板**由宿主渲染成
|
|
20
|
+
同样的结构,所以天然跟着一起折叠 —— 它们本来就是这组里的入口。
|
|
21
|
+
- 其余节点(别的插件直接注入的按钮、包装层、分隔线……)**一个字都不改**:不加标记、不改宽度/字号/文字;
|
|
22
|
+
收成一条时它们**原地留着、照样能点**(这时整只 nav 不隐藏,只藏面板行)。
|
|
23
|
+
- 关掉折叠时把标记与行内样式**全部还原**。
|
|
24
|
+
|
|
25
|
+
**测试**:`test/sidebar-nav.mjs` 新增第 6 节(9 条:分类、bar 模式保留别人的节点、icons 模式不碰别人的节点、
|
|
26
|
+
关掉后摘干净);变异新增 SX / SY 两条(把别人的节点当面板行、有别人的节点仍整体隐藏)。
|
|
27
|
+
|
|
5
28
|
## [0.28.0] — 2026-10-28(删掉四栏:微信通知 / 工作区目录选择 / 右键菜单 / OpenCode 请求头)
|
|
6
29
|
|
|
7
30
|
用户 2026-10-28:「我的插件去掉微信通知,去掉工作区目录选择,去掉右键菜单,去掉 open code 请求头」。
|
package/README.md
CHANGED
|
@@ -114,6 +114,24 @@ dsh plugin --profile web add <你克隆或解压出来的目录>
|
|
|
114
114
|
- 单个字母/数字键不允许裸绑定(会与打字冲突);纯修饰键不会触发录制。
|
|
115
115
|
- 部分 Ctrl/Meta 组合被浏览器占用(如 Ctrl+L、Ctrl+W、Ctrl+J),录制时无法在页面捕获——建议使用 Alt/Shift 组合或 Enter 系键位。
|
|
116
116
|
|
|
117
|
+
## 左侧「全局面板」折叠(0.27.0,0.28.1 起对别的插件友好)
|
|
118
|
+
|
|
119
|
+
侧边栏最上面那一组(插件 / 自动化任务 / 上下文洞察 / MCP连接器 / 更多)可以折叠,设置 →
|
|
120
|
+
输入体验 →「设置面板」卡 →「侧边栏」组:
|
|
121
|
+
|
|
122
|
+
| 形态 | 界面 | 说明 |
|
|
123
|
+
|---|---|---|
|
|
124
|
+
| **收成一条**(默认) | 一行「全局面板 ▾」 | 点一下展开成原来那几颗,再点收起 |
|
|
125
|
+
| **只留图标** | 一行图标 | 悬停出名字 |
|
|
126
|
+
| **不折叠** | DSH 原样 | 等于关掉这个功能 |
|
|
127
|
+
|
|
128
|
+
**"打开后默认折叠"是默认行为**:状态记在 `$DSH_HOME/composer-ux-nav-fold.json`,不占宿主设置字段。
|
|
129
|
+
|
|
130
|
+
**别的插件往这里放按钮怎么办(0.28.1)**:只处理**认得出的面板行**(`button` + `aria-label` + 内含
|
|
131
|
+
`aria-hidden` 的图标)。别的插件**通过官方 panel 注册表**注册的入口,宿主会渲染成同样的结构,
|
|
132
|
+
所以跟着一起折叠;而**直接往 DOM 里塞**的按钮/包装层**一个字都不改**——收成一条时它们原地留着、
|
|
133
|
+
照样能点(这时只藏面板行,不藏整只 `nav`)。这条有 9 条测试盯着(`test/sidebar-nav.mjs` 第 6 节)。
|
|
134
|
+
|
|
117
135
|
## 快捷指令与提示词优化
|
|
118
136
|
|
|
119
137
|
输入框工具行里、「展开」按钮的左侧有一个同款胶囊按钮「快捷指令」(槽位 `conversation.input.right`,order 89 < 官方「展开」的 90)。点开展开面板:
|
|
@@ -653,7 +671,7 @@ node build.mjs # 产出 lib/index.js + lib/client.js
|
|
|
653
671
|
# 里同版本的 npm 包(两者逐字节相同)——CI 上走的就是退路
|
|
654
672
|
npm test # 29 个套件;当前 2603 passed, 0 failed(2026-10-28 实测;CI 三平台同样全绿)
|
|
655
673
|
# 走 scripts/run-tests.mjs:顺带把"多少套件/多少条"记进 test/.last-run.json
|
|
656
|
-
npm run test:mutations # 手动跑:变异测试,证明那套护栏真的在咬人(
|
|
674
|
+
npm run test:mutations # 手动跑:变异测试,证明那套护栏真的在咬人(200 条,须单独跑)
|
|
657
675
|
# 同样记录结果,供下面的文档门禁核对
|
|
658
676
|
npm run gates # 发版门禁三条一起跑:tag 指向 / 包内容 / 文档数字
|
|
659
677
|
npm run check:tag # ① tag 名里的版本 == 该 tag 所指提交里的 package.json 版本
|
package/dsh-plugin.json
CHANGED
package/lib/client.js
CHANGED
|
@@ -2839,15 +2839,18 @@ var NAV_FOLD_ATTR = "data-ux-nav-fold";
|
|
|
2839
2839
|
var NAV_FOLD_HEAD_ATTR = "data-ux-nav-fold-head";
|
|
2840
2840
|
var NAV_FOLD_STYLE_ATTR = "data-ux-nav-fold-style";
|
|
2841
2841
|
var NAV_FOLD_TITLE_ATTR = "data-ux-nav-title";
|
|
2842
|
+
var NAV_FOLD_ROW_ATTR = "data-ux-nav-row";
|
|
2842
2843
|
function navFoldAttrOf(state3) {
|
|
2843
2844
|
if (state3.mode === "off") return null;
|
|
2844
2845
|
if (state3.mode === "icons") return "icons";
|
|
2845
2846
|
return state3.collapsed ? "bar-collapsed" : "bar-open";
|
|
2846
2847
|
}
|
|
2847
2848
|
var NAV_FOLD_CSS = `
|
|
2848
|
-
|
|
2849
|
+
/* \u26A0\uFE0F \u6240\u6709\u89C4\u5219\u90FD\u53EA\u8BA4 [${NAV_FOLD_ROW_ATTR}]\uFF08\u6211\u4EEC\u6807\u51FA\u6765\u7684\u9762\u677F\u884C\uFF09\uFF0C
|
|
2850
|
+
\u4E0D\u5199 nav > button \u2014\u2014 \u522B\u7684\u63D2\u4EF6\u5F80\u8FD9\u4E00\u7EC4\u91CC\u6CE8\u5165\u7684\u6309\u94AE/\u5305\u88C5\u5C42\u5FC5\u987B\u539F\u6837\u4E0D\u52A8\u3002 */
|
|
2851
|
+
nav[${NAV_FOLD_ATTR}='bar-collapsed'] > [${NAV_FOLD_ROW_ATTR}] { display: none !important; }
|
|
2849
2852
|
nav[${NAV_FOLD_ATTR}='icons'] { flex-direction: row; flex-wrap: wrap; gap: 4px; }
|
|
2850
|
-
nav[${NAV_FOLD_ATTR}='icons'] >
|
|
2853
|
+
nav[${NAV_FOLD_ATTR}='icons'] > [${NAV_FOLD_ROW_ATTR}] {
|
|
2851
2854
|
width: 34px;
|
|
2852
2855
|
min-width: 34px;
|
|
2853
2856
|
padding-left: 0;
|
|
@@ -2855,10 +2858,10 @@ nav[${NAV_FOLD_ATTR}='icons'] > button {
|
|
|
2855
2858
|
justify-content: center;
|
|
2856
2859
|
}
|
|
2857
2860
|
/* \u56FE\u6807\u90A3\u4E00\u9897\u5E26 aria-hidden\uFF0C\u6587\u5B57\u90A3\u9897\u4E0D\u5E26 \u2014\u2014 \u9760\u8BED\u4E49\u85CF\u6587\u5B57\uFF0C\u4E0D\u8BA4\u54C8\u5E0C\u7C7B\u540D\u3002 */
|
|
2858
|
-
nav[${NAV_FOLD_ATTR}='icons'] >
|
|
2861
|
+
nav[${NAV_FOLD_ATTR}='icons'] > [${NAV_FOLD_ROW_ATTR}] > span:not([aria-hidden='true']) { display: none !important; }
|
|
2859
2862
|
/* \u300C\u66F4\u591A\u300D\u90A3\u9897\u6309\u94AE\u7684\u6807\u7B7E\u662F**\u88F8\u6587\u672C\u8282\u70B9**\uFF08\u6CA1\u6709 span\uFF09\uFF0C\u4E0A\u9762\u90A3\u6761\u89C4\u5219\u7BA1\u4E0D\u5230\u5B83\uFF1B
|
|
2860
2863
|
\u6240\u4EE5\u56FE\u6807\u6A21\u5F0F\u518D\u8865\u4E00\u5200 fontSize:0\uFF08\u56FE\u6807\u662F SVG\uFF0C\u4E0D\u53D7\u5B57\u53F7\u5F71\u54CD\uFF09\u3002 */
|
|
2861
|
-
nav[${NAV_FOLD_ATTR}='icons'] >
|
|
2864
|
+
nav[${NAV_FOLD_ATTR}='icons'] > [${NAV_FOLD_ROW_ATTR}] { font-size: 0; }
|
|
2862
2865
|
[${NAV_FOLD_HEAD_ATTR}] {
|
|
2863
2866
|
display: flex;
|
|
2864
2867
|
align-items: center;
|
|
@@ -2900,8 +2903,8 @@ function ensureStyle(doc) {
|
|
|
2900
2903
|
}
|
|
2901
2904
|
if (tag.textContent !== NAV_FOLD_CSS) tag.textContent = NAV_FOLD_CSS;
|
|
2902
2905
|
}
|
|
2903
|
-
function applyTitles(
|
|
2904
|
-
for (const button of
|
|
2906
|
+
function applyTitles(rows, on) {
|
|
2907
|
+
for (const button of rows) {
|
|
2905
2908
|
if (on) {
|
|
2906
2909
|
const label = (button.getAttribute("aria-label") ?? "").trim();
|
|
2907
2910
|
if (label !== "" && button.getAttribute(NAV_FOLD_TITLE_ATTR) !== label) {
|
|
@@ -2923,6 +2926,23 @@ function applyTitles(nav, on) {
|
|
|
2923
2926
|
}
|
|
2924
2927
|
}
|
|
2925
2928
|
}
|
|
2929
|
+
function splitPanelRows(nav, mark = true) {
|
|
2930
|
+
const rows = [];
|
|
2931
|
+
const foreign = [];
|
|
2932
|
+
for (const child of [...nav.children]) {
|
|
2933
|
+
const label = (child.getAttribute("aria-label") ?? "").trim();
|
|
2934
|
+
const isRow = child.tagName === "BUTTON" && label !== "" && child.querySelector('[aria-hidden="true"]') !== null;
|
|
2935
|
+
const shouldMark = isRow && mark;
|
|
2936
|
+
if (!shouldMark) {
|
|
2937
|
+
if (child.hasAttribute(NAV_FOLD_ROW_ATTR)) child.removeAttribute(NAV_FOLD_ROW_ATTR);
|
|
2938
|
+
} else if (!child.hasAttribute(NAV_FOLD_ROW_ATTR)) {
|
|
2939
|
+
child.setAttribute(NAV_FOLD_ROW_ATTR, "");
|
|
2940
|
+
}
|
|
2941
|
+
if (isRow) rows.push(child);
|
|
2942
|
+
else foreign.push(child);
|
|
2943
|
+
}
|
|
2944
|
+
return { rows, foreign };
|
|
2945
|
+
}
|
|
2926
2946
|
function ensureHeader(doc, nav, state3, onToggle) {
|
|
2927
2947
|
const want = state3.mode === "bar";
|
|
2928
2948
|
let head = doc.querySelector(`button[${NAV_FOLD_HEAD_ATTR}]`);
|
|
@@ -2958,7 +2978,14 @@ function applyNavFold(doc, state3, onToggle) {
|
|
|
2958
2978
|
const attr = navFoldAttrOf(state3);
|
|
2959
2979
|
if (attr === null) nav.removeAttribute(NAV_FOLD_ATTR);
|
|
2960
2980
|
else if (nav.getAttribute(NAV_FOLD_ATTR) !== attr) nav.setAttribute(NAV_FOLD_ATTR, attr);
|
|
2961
|
-
|
|
2981
|
+
const { rows, foreign } = splitPanelRows(nav, state3.mode !== "off");
|
|
2982
|
+
applyTitles(rows, state3.mode === "icons");
|
|
2983
|
+
const hideWhole = state3.mode === "bar" && state3.collapsed && foreign.length === 0;
|
|
2984
|
+
if (hideWhole) {
|
|
2985
|
+
if (nav.style.display !== "none") nav.style.display = "none";
|
|
2986
|
+
} else if (nav.style.display === "none") {
|
|
2987
|
+
nav.style.display = "";
|
|
2988
|
+
}
|
|
2962
2989
|
ensureHeader(doc, nav, state3, onToggle);
|
|
2963
2990
|
return true;
|
|
2964
2991
|
}
|