dsh-sidebar-row-menu 1.3.3 → 1.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI_USAGE.en.md +2 -2
- package/AI_USAGE.md +2 -2
- package/README.en.md +9 -10
- package/README.md +8 -9
- package/lib/client.js +79 -51
- package/package.json +1 -1
package/AI_USAGE.en.md
CHANGED
|
@@ -70,10 +70,10 @@ Not fully verified:
|
|
|
70
70
|
|
|
71
71
|
- The plugin runs locally and contains **no telemetry, analytics or remote requests**.
|
|
72
72
|
- The client reads workspace/session objects already in DSH's memory (title, `cwd`,
|
|
73
|
-
archived/pinned state) to build menus and copy paths
|
|
73
|
+
archived/pinned state) to build menus and copy paths.
|
|
74
74
|
- The host route accepts loopback requests only and opens **existing absolute
|
|
75
75
|
directories** only.
|
|
76
|
-
- Clipboard writes happen only when you click "Copy path / Copy
|
|
76
|
+
- Clipboard writes happen only when you click "Copy workspace path / Copy Session ID".
|
|
77
77
|
|
|
78
78
|
## 7. Recommendations
|
|
79
79
|
|
package/AI_USAGE.md
CHANGED
|
@@ -61,9 +61,9 @@
|
|
|
61
61
|
|
|
62
62
|
- 插件在本地运行,**不包含遥测、统计上报或远程请求**。
|
|
63
63
|
- 客户端只读取 DSH 已渲染到内存中的工作区/会话对象(标题、`cwd`、归档/置顶状态),
|
|
64
|
-
|
|
64
|
+
用于生成菜单与复制路径。
|
|
65
65
|
- 宿主路由只接受本机(loopback)请求,且只打开**已存在的绝对目录**。
|
|
66
|
-
-
|
|
66
|
+
- 剪贴板写入仅发生在你点击“复制工作区路径 / 复制 Session ID”时。
|
|
67
67
|
|
|
68
68
|
## 7. 使用建议
|
|
69
69
|
|
package/README.en.md
CHANGED
|
@@ -48,17 +48,16 @@ Right-click does not build a second menu; it opens the row's own "…" menu:
|
|
|
48
48
|
| --- | --- |
|
|
49
49
|
| DSH built-ins | Rename, Fork session, Pin / Unpin, Archive / Unarchive, Copy Session ID |
|
|
50
50
|
| Other plugins | Whatever they register into `sidebar.workspaces.session.menu.item` |
|
|
51
|
-
| This plugin | Open in VS Code, Open in Explorer
|
|
51
|
+
| This plugin | Open in VS Code, Open in Explorer |
|
|
52
52
|
|
|
53
|
-
The
|
|
53
|
+
The two entries added by this plugin:
|
|
54
54
|
|
|
55
55
|
| Item | Behavior |
|
|
56
56
|
| --- | --- |
|
|
57
57
|
| Open in VS Code | Uses the session's `cwd`, falling back to its workspace directory |
|
|
58
58
|
| Open in Explorer | Same as above |
|
|
59
|
-
| Copy session link | Copies the `?session=<id>` deep link |
|
|
60
59
|
|
|
61
|
-
These
|
|
60
|
+
These two are **right-click only**: they do not mount when the "…" button opens
|
|
62
61
|
the menu. A short-lived window flag is set before opening; outside that window the
|
|
63
62
|
entries render `null`.
|
|
64
63
|
|
|
@@ -90,13 +89,13 @@ resolve it directly by name:
|
|
|
90
89
|
Pin a version by appending it to the name:
|
|
91
90
|
|
|
92
91
|
```
|
|
93
|
-
dsh-sidebar-row-menu@1.3.
|
|
92
|
+
dsh-sidebar-row-menu@1.3.5
|
|
94
93
|
```
|
|
95
94
|
|
|
96
95
|
Equivalent command line:
|
|
97
96
|
|
|
98
97
|
```powershell
|
|
99
|
-
dsh plugin --profile desktop add dsh-sidebar-row-menu@1.3.
|
|
98
|
+
dsh plugin --profile desktop add dsh-sidebar-row-menu@1.3.5
|
|
100
99
|
```
|
|
101
100
|
|
|
102
101
|
### Install from GitHub
|
|
@@ -116,13 +115,13 @@ repository is already runnable, so **no local build is required**.
|
|
|
116
115
|
That URL tracks the latest commit on `main`. Pin a tag for a stable version:
|
|
117
116
|
|
|
118
117
|
```
|
|
119
|
-
https://github.com/TLEWA/dsh-sidebar-row-menu#v1.3.
|
|
118
|
+
https://github.com/TLEWA/dsh-sidebar-row-menu#v1.3.5
|
|
120
119
|
```
|
|
121
120
|
|
|
122
121
|
Or install the tarball built by Actions directly, without Git:
|
|
123
122
|
|
|
124
123
|
```
|
|
125
|
-
https://github.com/TLEWA/dsh-sidebar-row-menu/releases/download/v1.3.
|
|
124
|
+
https://github.com/TLEWA/dsh-sidebar-row-menu/releases/download/v1.3.5/dsh-sidebar-row-menu-1.3.5.tgz
|
|
126
125
|
```
|
|
127
126
|
|
|
128
127
|
Equivalent command line:
|
|
@@ -244,8 +243,8 @@ loopback checks, route status codes) and the client module (module id, exports,
|
|
|
244
243
|
dependency whitelist, listener install/uninstall, slot registry). Integration
|
|
245
244
|
tests use a fake `__reactFiber$`, DOM and `Menu` host to assert workspace menu
|
|
246
245
|
ordering, session right-click delegating to the native menu, blank rows being
|
|
247
|
-
skipped, and
|
|
248
|
-
a manual check in a running GUI.
|
|
246
|
+
skipped, and the success toast shown when copying a workspace path. Real fibers and
|
|
247
|
+
services still need a manual check in a running GUI.
|
|
249
248
|
|
|
250
249
|
Layout:
|
|
251
250
|
|
package/README.md
CHANGED
|
@@ -42,17 +42,16 @@
|
|
|
42
42
|
| --- | --- |
|
|
43
43
|
| DSH 内置 | 重命名、分叉会话、置顶 / 取消置顶、归档 / 取消归档、复制 Session ID |
|
|
44
44
|
| 其他插件 | 它们注册进 `sidebar.workspaces.session.menu.item` 的条目 |
|
|
45
|
-
| 本插件 | 使用 VS Code
|
|
45
|
+
| 本插件 | 使用 VS Code 打开、在资源管理器中打开 |
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
本插件追加的两个条目:
|
|
48
48
|
|
|
49
49
|
| 菜单项 | 行为 |
|
|
50
50
|
| --- | --- |
|
|
51
51
|
| 使用 VS Code 打开 | 优先用会话自己的 `cwd`,取不到则用所属工作区目录 |
|
|
52
52
|
| 在资源管理器中打开 | 同上 |
|
|
53
|
-
| 复制会话链接 | 复制 `?session=<id>` 深链接 |
|
|
54
53
|
|
|
55
|
-
|
|
54
|
+
这两条是**右键专属**:点行尾「…」按钮时它们不挂载。实现上使用一个只在右键展开瞬间
|
|
56
55
|
有效的窗口标记,窗口外的渲染直接返回 `null`。
|
|
57
56
|
|
|
58
57
|
草稿会话(还没有任何消息的空白会话)没有内置「…」菜单,本插件同样不接管。
|
|
@@ -82,13 +81,13 @@
|
|
|
82
81
|
要固定版本,在包名后加版本号:
|
|
83
82
|
|
|
84
83
|
```
|
|
85
|
-
dsh-sidebar-row-menu@1.3.
|
|
84
|
+
dsh-sidebar-row-menu@1.3.5
|
|
86
85
|
```
|
|
87
86
|
|
|
88
87
|
命令行等价写法:
|
|
89
88
|
|
|
90
89
|
```powershell
|
|
91
|
-
dsh plugin --profile desktop add dsh-sidebar-row-menu@1.3.
|
|
90
|
+
dsh plugin --profile desktop add dsh-sidebar-row-menu@1.3.5
|
|
92
91
|
```
|
|
93
92
|
|
|
94
93
|
### 从 GitHub 安装
|
|
@@ -108,13 +107,13 @@ DSH 桌面端通过 pnpm 安装 Git 依赖;本仓库的 `lib/` 已是可直接
|
|
|
108
107
|
该地址跟随 `main` 的最新提交。要固定版本,在地址后加标签:
|
|
109
108
|
|
|
110
109
|
```
|
|
111
|
-
https://github.com/TLEWA/dsh-sidebar-row-menu#v1.3.
|
|
110
|
+
https://github.com/TLEWA/dsh-sidebar-row-menu#v1.3.5
|
|
112
111
|
```
|
|
113
112
|
|
|
114
113
|
也可以直接安装 Actions 打出的压缩包(不经过 Git):
|
|
115
114
|
|
|
116
115
|
```
|
|
117
|
-
https://github.com/TLEWA/dsh-sidebar-row-menu/releases/download/v1.3.
|
|
116
|
+
https://github.com/TLEWA/dsh-sidebar-row-menu/releases/download/v1.3.5/dsh-sidebar-row-menu-1.3.5.tgz
|
|
118
117
|
```
|
|
119
118
|
|
|
120
119
|
命令行等价写法:
|
|
@@ -219,7 +218,7 @@ npm run build # npm pack(prepack 会先跑 check),产出 .tgz
|
|
|
219
218
|
测试覆盖宿主侧纯函数(路径校验、`vscode://file` 编码、loopback 判定、路由状态码)
|
|
220
219
|
和客户端模块(模块 id、导出、依赖白名单、监听器安装/卸载、slot 注册表),并用伪造的
|
|
221
220
|
`__reactFiber$`、DOM 与 `Menu` 宿主做集成测试:工作区右键的菜单项顺序、会话右键是否
|
|
222
|
-
|
|
221
|
+
展开内置菜单而不是自建菜单、草稿行是否被放过、复制工作区路径的 Toast 反馈都在断言里。
|
|
223
222
|
真实 fiber 与服务仍需在运行中的 GUI 里做人工验证。
|
|
224
223
|
|
|
225
224
|
目录:
|
package/lib/client.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* 会话行:直接展开该行内置的「…」菜单
|
|
11
11
|
* 重命名、分叉、置顶、归档、复制 Session ID 等条目由各自注册进
|
|
12
12
|
* `sidebar.workspaces.session.menu.item` 的插件提供,本插件不复制、不硬编码。
|
|
13
|
-
* 本插件只往这个 slot 里追加自己的条目(VS Code /
|
|
13
|
+
* 本插件只往这个 slot 里追加自己的条目(VS Code / 资源管理器),
|
|
14
14
|
* 所以它们既出现在「…」菜单里,也自动出现在右键菜单里。
|
|
15
15
|
*
|
|
16
16
|
* 设计要点:
|
|
@@ -50,6 +50,7 @@ window.__ModuleLoader__.load({
|
|
|
50
50
|
const {
|
|
51
51
|
Menu,
|
|
52
52
|
MenuItemButton,
|
|
53
|
+
Toast,
|
|
53
54
|
writeClipboard,
|
|
54
55
|
IconEditOutlineRegular,
|
|
55
56
|
IconTrashOutlineRegular,
|
|
@@ -57,7 +58,7 @@ window.__ModuleLoader__.load({
|
|
|
57
58
|
IconFolderOpenRegular,
|
|
58
59
|
IconProjectAddOutlineRegular,
|
|
59
60
|
IconNewChatOutlineRegular,
|
|
60
|
-
|
|
61
|
+
IconWarningOutlineRegular,
|
|
61
62
|
IconCopyOutlineRegular,
|
|
62
63
|
} = require('@deepseek-ai/dsh-client-ui-primitives');
|
|
63
64
|
|
|
@@ -65,6 +66,8 @@ window.__ModuleLoader__.load({
|
|
|
65
66
|
const OPEN_ENDPOINT = '/dsh-sidebar-row-menu/open';
|
|
66
67
|
/** 运行时探测用标记属性(也是离线冒烟测试的抓手)。 */
|
|
67
68
|
const MENU_ATTR = 'data-dsh-sidebar-row-menu';
|
|
69
|
+
/** 复制反馈的官方 Toast 挂载点。 */
|
|
70
|
+
const TOAST_ATTR = 'data-dsh-sidebar-row-menu-toast';
|
|
68
71
|
/** 本地化命名空间。 */
|
|
69
72
|
const NS = 'sidebar-row-menu';
|
|
70
73
|
/** 内置「…」菜单的扩展点;条目由各插件自行注册。 */
|
|
@@ -78,7 +81,6 @@ window.__ModuleLoader__.load({
|
|
|
78
81
|
vscode: '使用 VS Code 打开',
|
|
79
82
|
explorer: '在资源管理器中打开',
|
|
80
83
|
copyPath: '复制工作区路径',
|
|
81
|
-
copyLink: '复制会话链接',
|
|
82
84
|
openInTab: '在新标签中打开',
|
|
83
85
|
deleteWorkspace: '删除工作区',
|
|
84
86
|
copied: '已复制',
|
|
@@ -93,7 +95,6 @@ window.__ModuleLoader__.load({
|
|
|
93
95
|
vscode: 'Open in VS Code',
|
|
94
96
|
explorer: 'Reveal in File Explorer',
|
|
95
97
|
copyPath: 'Copy workspace path',
|
|
96
|
-
copyLink: 'Copy session link',
|
|
97
98
|
openInTab: 'Open in new tab',
|
|
98
99
|
deleteWorkspace: 'Delete workspace',
|
|
99
100
|
copied: 'Copied',
|
|
@@ -205,29 +206,48 @@ window.__ModuleLoader__.load({
|
|
|
205
206
|
|
|
206
207
|
/* ------------------------------------------------------------ 小工具 */
|
|
207
208
|
|
|
208
|
-
/**
|
|
209
|
-
|
|
209
|
+
/**
|
|
210
|
+
* 轻提示:直接用官方 Toast primitive(与内置「复制 Session ID」同款、
|
|
211
|
+
* 同一个底部居中 portal),不再自绘 DOM 气泡。
|
|
212
|
+
*/
|
|
213
|
+
let toastHost = null;
|
|
214
|
+
let toastRoot = null;
|
|
215
|
+
|
|
216
|
+
function closeToast() {
|
|
217
|
+
const host = toastHost;
|
|
218
|
+
const root = toastRoot;
|
|
219
|
+
toastHost = null;
|
|
220
|
+
toastRoot = null;
|
|
221
|
+
if (root !== null) {
|
|
222
|
+
try {
|
|
223
|
+
root.unmount();
|
|
224
|
+
} catch {
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (host !== null) host.remove();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function toast(message, tone) {
|
|
210
231
|
if (document.body === null) return;
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
'left:
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
'
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
window.setTimeout(() => el.remove(), 2600);
|
|
232
|
+
closeToast();
|
|
233
|
+
const host = document.createElement('div');
|
|
234
|
+
host.setAttribute(TOAST_ATTR, '');
|
|
235
|
+
host.style.cssText =
|
|
236
|
+
'position:fixed;left:0;top:0;width:0;height:0;z-index:2147483647;pointer-events:none';
|
|
237
|
+
document.body.appendChild(host);
|
|
238
|
+
const root = createRoot(host);
|
|
239
|
+
toastHost = host;
|
|
240
|
+
toastRoot = root;
|
|
241
|
+
const props = {
|
|
242
|
+
text: message,
|
|
243
|
+
onDone: () => window.setTimeout(closeToast, 0),
|
|
244
|
+
};
|
|
245
|
+
if (tone === 'success') props.tone = 'success';
|
|
246
|
+
if (tone === 'warning') {
|
|
247
|
+
props.tone = 'warning';
|
|
248
|
+
props.icon = jsx(IconWarningOutlineRegular, {});
|
|
249
|
+
}
|
|
250
|
+
root.render(jsx(Toast, props));
|
|
231
251
|
}
|
|
232
252
|
|
|
233
253
|
/** 取客户端服务;cordis 对未 inject 的服务在属性访问时也会抛错,全部兜住。 */
|
|
@@ -277,20 +297,13 @@ window.__ModuleLoader__.load({
|
|
|
277
297
|
async function copyText(text, t) {
|
|
278
298
|
try {
|
|
279
299
|
const ok = await writeClipboard(text);
|
|
280
|
-
toast(ok ? t('copied') : t('copyFailed'));
|
|
300
|
+
toast(ok ? t('copied') : t('copyFailed'), ok ? 'success' : 'warning');
|
|
281
301
|
} catch (error) {
|
|
282
302
|
console.warn('[dsh-sidebar-row-menu] clipboard failed:', error);
|
|
283
|
-
toast(t('copyFailed'));
|
|
303
|
+
toast(t('copyFailed'), 'warning');
|
|
284
304
|
}
|
|
285
305
|
}
|
|
286
306
|
|
|
287
|
-
/** ?session=<id> 深链接(与 dsh-workspace-menu / 内置 toast 的格式一致)。 */
|
|
288
|
-
function deepLink(sessionId) {
|
|
289
|
-
const url = new URL(window.location.href);
|
|
290
|
-
url.searchParams.set('session', sessionId);
|
|
291
|
-
return url.toString();
|
|
292
|
-
}
|
|
293
|
-
|
|
294
307
|
function workspaceCwd(ctx, group) {
|
|
295
308
|
if (typeof group?.cwd === 'string' && group.cwd !== '') return group.cwd;
|
|
296
309
|
const workspaces = serviceOf(ctx, 'workspaces');
|
|
@@ -487,21 +500,6 @@ window.__ModuleLoader__.load({
|
|
|
487
500
|
});
|
|
488
501
|
}
|
|
489
502
|
|
|
490
|
-
/** 会话菜单条目:复制会话链接。 */
|
|
491
|
-
function SessionCopyLinkMenuItem({ sessionId, useMenuOpenState, t }) {
|
|
492
|
-
const visible = useRightClickEntry();
|
|
493
|
-
const [, setMenuOpen] = useMenuOpenState();
|
|
494
|
-
if (!visible) return null;
|
|
495
|
-
return jsx(MenuItemButton, {
|
|
496
|
-
icon: jsx(IconLinkOutlineRegular, { size: 14 }),
|
|
497
|
-
onSelect: () => {
|
|
498
|
-
setMenuOpen(false);
|
|
499
|
-
copyText(deepLink(sessionId), t);
|
|
500
|
-
},
|
|
501
|
-
children: t('copyLink'),
|
|
502
|
-
});
|
|
503
|
-
}
|
|
504
|
-
|
|
505
503
|
/**
|
|
506
504
|
* 把本插件自己的会话动作注册进内置「…」菜单的 slot。
|
|
507
505
|
* 排序放在内置条目之后(pin 100 / rename 200 / fork 300 / archive 400 /
|
|
@@ -511,7 +509,6 @@ window.__ModuleLoader__.load({
|
|
|
511
509
|
const entries = [
|
|
512
510
|
{ id: 'row-menu-vscode', order: 500, Component: SessionVscodeMenuItem },
|
|
513
511
|
{ id: 'row-menu-explorer', order: 510, Component: SessionExplorerMenuItem },
|
|
514
|
-
{ id: 'row-menu-copy-link', order: 520, Component: SessionCopyLinkMenuItem },
|
|
515
512
|
];
|
|
516
513
|
return ctx.slots.inject(SESSION_MENU_SLOT, function* () {
|
|
517
514
|
for (const entry of entries) {
|
|
@@ -649,6 +646,35 @@ window.__ModuleLoader__.load({
|
|
|
649
646
|
return null;
|
|
650
647
|
}
|
|
651
648
|
|
|
649
|
+
/**
|
|
650
|
+
* 有些插件(例如 meow-memory 的「记忆参与」)在菜单打开后才用
|
|
651
|
+
* MutationObserver 往面板里补一个 DOM 条目;它们只有在收到行内「…」
|
|
652
|
+
* 按钮的 pointerdown 时才走同步注入的快路径,否则要等约 120ms 的防抖,
|
|
653
|
+
* 表现就是菜单先出现、条目晚一拍再冒出来,触发一次可见的重排。
|
|
654
|
+
*
|
|
655
|
+
* 右键发生在行标题等位置,天然不会点到「…」按钮,所以这里补发一次
|
|
656
|
+
* pointerdown,让这类插件在菜单挂载的同一帧完成注入。事件只用于通知,
|
|
657
|
+
* 不派发 click,也不会二次打开菜单。
|
|
658
|
+
*/
|
|
659
|
+
function primeRowActionPointer(trigger) {
|
|
660
|
+
if (trigger === null || trigger === undefined || typeof trigger.dispatchEvent !== 'function') return;
|
|
661
|
+
if (typeof PointerEvent !== 'function') return;
|
|
662
|
+
try {
|
|
663
|
+
trigger.dispatchEvent(new PointerEvent('pointerdown', {
|
|
664
|
+
bubbles: true,
|
|
665
|
+
cancelable: true,
|
|
666
|
+
composed: true,
|
|
667
|
+
pointerId: 1,
|
|
668
|
+
pointerType: 'mouse',
|
|
669
|
+
isPrimary: true,
|
|
670
|
+
button: 0,
|
|
671
|
+
buttons: 1,
|
|
672
|
+
}));
|
|
673
|
+
} catch {
|
|
674
|
+
/* 第三方 pointerdown 监听器抛错不应影响菜单打开 */
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
652
678
|
/**
|
|
653
679
|
* 右键会话行时在指针处展开该行自带的「…」菜单。
|
|
654
680
|
* 菜单内容来自 slot 注册表:内置条目和第三方条目都在,本插件不复制内置动作;
|
|
@@ -667,6 +693,7 @@ window.__ModuleLoader__.load({
|
|
|
667
693
|
window.setTimeout(() => {
|
|
668
694
|
rightClickMenuUntil = 0;
|
|
669
695
|
}, 600);
|
|
696
|
+
primeRowActionPointer(trigger);
|
|
670
697
|
if (menu !== null) {
|
|
671
698
|
menu.anchor.props.onClick();
|
|
672
699
|
return;
|
|
@@ -717,6 +744,7 @@ window.__ModuleLoader__.load({
|
|
|
717
744
|
return () => {
|
|
718
745
|
window.removeEventListener('contextmenu', onContextMenu, true);
|
|
719
746
|
closeMenu();
|
|
747
|
+
closeToast();
|
|
720
748
|
};
|
|
721
749
|
}
|
|
722
750
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-sidebar-row-menu",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DSH sidebar right-click menus: a self-composed menu for workspace rows, and the native slot menu opened at the pointer for session rows.",
|
|
6
6
|
"keywords": [
|