dsh-sidebar-row-menu 1.3.4 → 1.4.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/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/links.
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 link / Copy ID".
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
- - 剪贴板写入仅发生在你点击“复制路径 / 复制链接 / 复制 ID”时。
66
+ - 剪贴板写入仅发生在你点击“复制工作区路径 / 复制 Session ID”时。
67
67
 
68
68
  ## 7. 使用建议
69
69
 
package/CHANGELOG.md ADDED
@@ -0,0 +1,69 @@
1
+ # Changelog
2
+
3
+ ## 1.4.0 — 2026-11-03
4
+
5
+ ### Added
6
+
7
+ - **Open with** submenu on both workspace and session row menus. The app list comes
8
+ from DSH's built-in `open-in-app` endpoints (`/open-in-app/apps`,
9
+ `/open-in-app/open`, `/open-in-app/icon/<id>`), so it matches the apps DSH itself
10
+ offers. Hovering the row expands the submenu.
11
+ - **Pinned open-with apps**: a pinned app is shown directly at the top level (for
12
+ example "Open with Visual Studio Code"). Until configured, the first detected
13
+ editor is pinned automatically, otherwise the first catalog app. Pinning and
14
+ per-app visibility live in the plugin settings.
15
+ - **Delete session**: permanently deletes one archived session and its transcript.
16
+ The entry only appears on archived sessions.
17
+ - **Delete all archived sessions**: permanently deletes every archived session and
18
+ its transcript, again only from an archived row.
19
+ - **Settings section** ("Row menu") with switches for open with, delete session and
20
+ delete archived sessions, plus per-app visibility and pinning. Settings are stored
21
+ in `localStorage` and apply immediately.
22
+ - **Host route** `POST /dsh-sidebar-row-menu/session/delete` with the same loopback
23
+ fence as the open route; it stops a running session, detaches it, removes the
24
+ transcript directory after verifying its name, then clears archive/pin state and
25
+ emits `api-session/removed`.
26
+ - **Coexistence detection** with `dsh-session-menu`: when it is installed and owns a
27
+ matching entry (`session-menu-open-with`, `session-menu-delete`,
28
+ `session-menu-delete-archived`), the duplicate entry from this plugin is hidden and
29
+ the settings row explains the conflict.
30
+
31
+ ### Changed
32
+
33
+ - The workspace row menu is now drawn with `MenuSurface` + `MenuItemButton`, sharing
34
+ the same open-with submenu, app catalog and pinning as the session menu. The old
35
+ flat "Open in VS Code" / "Open in Explorer" items were replaced.
36
+ - Session row entries are now "pinned app" + "Open with" + archived-session deletion
37
+ instead of the flat VS Code / Explorer items.
38
+ - Group separators are back in both menus.
39
+ - Custom submenu panels use `role="group"` so meow-memory's `[role="menu"]` injection
40
+ does not add a fake "memory participation" row inside them.
41
+
42
+ ### Notes
43
+
44
+ - Permanent deletion is irreversible. It only applies to archived sessions, does not
45
+ cascade to forked child sessions, and there is no recycle bin.
46
+ - The open-with feature needs DSH with the built-in `open-in-app` routes; on hosts
47
+ without them the submenu shows an "apps unavailable" hint.
48
+
49
+ ### 中文摘要
50
+
51
+ - 工作区 / 会话右键菜单新增「打开方式」二级菜单(复用 DSH 内置 `open-in-app` 应用列表),
52
+ 常用应用可置顶到一级菜单,默认自动置顶第一个编辑器。
53
+ - 已归档会话新增「永久删除会话」和「删除所有已归档会话」,由本插件宿主路由完成,
54
+ 不级联删除 fork 子会话,无回收站。
55
+ - 设置 →「行菜单」新增各项开关、应用逐个显隐与置顶。
56
+ - 与 `dsh-session-menu` 共存时自动隐藏重复条目,并在设置里说明冲突。
57
+ - 工作区菜单改为 `MenuSurface` + `MenuItemButton` 自绘以支持子菜单,恢复分组分隔线。
58
+
59
+ ## 1.3.5
60
+
61
+ - Release 1.3.5. See the GitHub release notes for details.
62
+
63
+ ## 1.3.4
64
+
65
+ - Use the official toast for copy feedback and remove the redundant session-link item.
66
+
67
+ ## 1.3.3
68
+
69
+ - Prime the row action pointer so menu extensions render in the first frame.
package/NOTICE.en.md CHANGED
@@ -17,8 +17,8 @@ adapted portions; all remaining code is copyright its contributors.
17
17
  detection, `vscode://file` encoding (now split across
18
18
  `lib/host/security.js`, `lib/host/launch.js`, `lib/host/paths.js`,
19
19
  `lib/host/route.js`);
20
- - client: fiber lookup, official `Menu` mounting, toast, capture-phase
21
- `contextmenu` installation.
20
+ - client: fiber lookup, official `Menu` mounting, `MenuSurface`/`MenuItemButton`
21
+ drawn rows, toast, capture-phase `contextmenu` installation.
22
22
 
23
23
  ## dsh-workspace-menu
24
24
 
package/NOTICE.md CHANGED
@@ -15,7 +15,8 @@
15
15
  - 宿主:loopback 围栏、JSON 请求体读取、detached spawn、VS Code 启动器探测、
16
16
  `vscode://file` 编码(现拆分在 `lib/host/security.js`、`lib/host/launch.js`、
17
17
  `lib/host/paths.js`、`lib/host/route.js`);
18
- - 客户端:fiber 解析、官方 `Menu` 挂载、toast、`contextmenu` 捕获安装方式。
18
+ - 客户端:fiber 解析、官方 `Menu` 挂载、`MenuSurface`/`MenuItemButton` 自绘行、
19
+ toast、`contextmenu` 捕获安装方式。
19
20
 
20
21
  ## dsh-workspace-menu
21
22
 
package/README.en.md CHANGED
@@ -14,15 +14,16 @@ Right-click menus for the sidebar of [DeepSeek Harness](https://github.com/deeps
14
14
  - **Session rows nested under a workspace** — right-click opens that row's native
15
15
  "…" menu at the pointer, with the plugin's own entries appended.
16
16
 
17
- Menus are rendered with DSH's official `Menu` component, so visuals, positioning,
18
- keyboard navigation and click-outside dismissal match the built-in "…" menus.
19
- The workspace menu is composed by this plugin. Session menu content comes from the
17
+ The workspace menu is drawn with DSH's official `MenuSurface` + `MenuItemButton`
18
+ (the official `Menu` cannot nest submenus), so rows, icons, danger color and group
19
+ separators reuse the built-in look, and keyboard navigation plus click-outside
20
+ dismissal match the native menus. Session menu content comes from the
20
21
  `sidebar.workspaces.session.menu.item` slot — built-in actions and other plugins'
21
22
  actions are all there. This plugin only appends its own entries; it does not copy
22
23
  or hardcode any built-in action.
23
24
 
24
- > The "…" button menu stays exactly as DSH ships it. The plugin's three entries
25
- > appear only when the menu is opened by right-click. A right-click menu does not
25
+ > The "…" button menu stays exactly as DSH ships it. The plugin's entries appear
26
+ > only when the menu is opened by right-click. A right-click menu does not
26
27
  > close when the pointer leaves it (same as the workspace menu); it closes only on
27
28
  > an outside click, an item selection, or Escape.
28
29
 
@@ -34,8 +35,8 @@ or hardcode any built-in action.
34
35
  | --- | --- |
35
36
  | New session | Expands the workspace and starts a session (same as the row's `+`) |
36
37
  | Rename | Opens the official "Rename workspace" dialog |
37
- | Open in VS Code | Host opens the workspace directory in a new window |
38
- | Open in Explorer | Host opens the system file manager |
38
+ | Pinned open-with app | A pinned app shows directly at the top level (e.g. "Open with Visual Studio Code") and opens the workspace directory |
39
+ | Open with | A submenu of external apps (editors, terminals, file managers) sharing the session menu's catalog, pinning and toggles; hover expands it |
39
40
  | Copy workspace path | Copies the directory path |
40
41
  | Open in new tab | Only when `dsh-project-tabs` (exposing `openWorkspaceInTab`) is installed |
41
42
  | Delete workspace | Opens the official delete confirmation |
@@ -48,23 +49,56 @@ Right-click does not build a second menu; it opens the row's own "…" menu:
48
49
  | --- | --- |
49
50
  | DSH built-ins | Rename, Fork session, Pin / Unpin, Archive / Unarchive, Copy Session ID |
50
51
  | Other plugins | Whatever they register into `sidebar.workspaces.session.menu.item` |
51
- | This plugin | Open in VS Code, Open in Explorer, Copy session link |
52
+ | This plugin | Pinned open-with apps (top level), Open with (submenu), Delete session / Delete all archived sessions (archived rows only) |
52
53
 
53
- The three entries added by this plugin:
54
+ The entries added by this plugin:
54
55
 
55
56
  | Item | Behavior |
56
57
  | --- | --- |
57
- | Open in VS Code | Uses the session's `cwd`, falling back to its workspace directory |
58
- | Open in Explorer | Same as above |
59
- | Copy session link | Copies the `?session=<id>` deep link |
60
-
61
- These three are **right-click only**: they do not mount when the "…" button opens
58
+ | Open with | A submenu of external apps provided by the host (editors, terminals, file managers) opening the session's `cwd`; falls back to its workspace directory. Hovering the row expands the submenu |
59
+ | Pinned open-with app | A pinned app shows directly at the top level (e.g. "Open with Visual Studio Code"). Until configured, the first detected editor is pinned automatically, otherwise the first catalog app |
60
+ | Delete session | Only on archived sessions; permanently deletes that one session and its transcript after confirmation |
61
+ | Delete all archived sessions | Only on archived sessions; permanently deletes every archived session and its transcript after confirmation |
62
+
63
+ The "Open with" catalog comes from DSH's built-in `open-in-app` routes, so it is the
64
+ same source DSH itself uses; labels and icons are rendered by this plugin, each app
65
+ can be hidden in Settings, and frequently used apps can be pinned to the top level.
66
+ Both delete entries are served by this plugin's own host route. They never
67
+ touch unarchived sessions and do not cascade into forked child sessions.
68
+
69
+ These entries are **right-click only**: they do not mount when the "…" button opens
62
70
  the menu. A short-lived window flag is set before opening; outside that window the
63
71
  entries render `null`.
64
72
 
65
73
  Blank draft sessions have no native "…" menu and are left alone. Rows that are
66
74
  neither a workspace nor a session (e.g. "Show more") are not intercepted.
67
75
 
76
+ ### Settings
77
+
78
+ Settings → "Row menu" toggles every new entry:
79
+
80
+ | Switch | Effect |
81
+ | --- | --- |
82
+ | Open with | Hides "Open with" and every pinned app from workspace and session menus |
83
+ | Open with → applications | Hides individual applications; the adjacent "Pin" button promotes an app to the top level |
84
+ | Delete session | Hides the single-session delete entry on archived rows |
85
+ | Delete all archived sessions | Hides the bulk-delete entry |
86
+
87
+ Switches live in browser `localStorage` (`dsh.sidebar-row-menu.items.v1`,
88
+ `dsh.sidebar-row-menu.open-with.v1` and `dsh.sidebar-row-menu.open-with.pinned.v1`)
89
+ and apply immediately. Before the first explicit pin, the plugin derives one: the
90
+ first detected editor (usually VS Code), or the first catalog app when no editor
91
+ exists.
92
+
93
+ ### Coexistence with dsh-session-menu
94
+
95
+ When [`dsh-session-menu`](https://github.com/big-head-pigeon/dsh-session-menu) is
96
+ installed, this plugin looks for its `session-menu-open-with` /
97
+ `session-menu-delete` / `session-menu-delete-archived` entries in the session menu slot. If present, the
98
+ matching entries here are hidden and the settings switches are disabled with a
99
+ "provided by dsh-session-menu" hint. No configuration of the other plugin is read
100
+ or changed.
101
+
68
102
  ## Install
69
103
 
70
104
  Requirements:
@@ -90,13 +124,13 @@ resolve it directly by name:
90
124
  Pin a version by appending it to the name:
91
125
 
92
126
  ```
93
- dsh-sidebar-row-menu@1.3.4
127
+ dsh-sidebar-row-menu@1.4.0
94
128
  ```
95
129
 
96
130
  Equivalent command line:
97
131
 
98
132
  ```powershell
99
- dsh plugin --profile desktop add dsh-sidebar-row-menu@1.3.4
133
+ dsh plugin --profile desktop add dsh-sidebar-row-menu@1.4.0
100
134
  ```
101
135
 
102
136
  ### Install from GitHub
@@ -116,13 +150,13 @@ repository is already runnable, so **no local build is required**.
116
150
  That URL tracks the latest commit on `main`. Pin a tag for a stable version:
117
151
 
118
152
  ```
119
- https://github.com/TLEWA/dsh-sidebar-row-menu#v1.3.4
153
+ https://github.com/TLEWA/dsh-sidebar-row-menu#v1.4.0
120
154
  ```
121
155
 
122
156
  Or install the tarball built by Actions directly, without Git:
123
157
 
124
158
  ```
125
- https://github.com/TLEWA/dsh-sidebar-row-menu/releases/download/v1.3.4/dsh-sidebar-row-menu-1.3.4.tgz
159
+ https://github.com/TLEWA/dsh-sidebar-row-menu/releases/download/v1.4.0/dsh-sidebar-row-menu-1.4.0.tgz
126
160
  ```
127
161
 
128
162
  Equivalent command line:
@@ -244,8 +278,8 @@ loopback checks, route status codes) and the client module (module id, exports,
244
278
  dependency whitelist, listener install/uninstall, slot registry). Integration
245
279
  tests use a fake `__reactFiber$`, DOM and `Menu` host to assert workspace menu
246
280
  ordering, session right-click delegating to the native menu, blank rows being
247
- skipped, and clipboard content for copy-link. Real fibers and services still need
248
- a manual check in a running GUI.
281
+ skipped, and the success toast shown when copying a workspace path. Real fibers and
282
+ services still need a manual check in a running GUI.
249
283
 
250
284
  Layout:
251
285
 
@@ -254,7 +288,8 @@ lib/index.js host entry: name / inject / apply plus re-exported helpers
254
288
  lib/host/security.js loopback request fence
255
289
  lib/host/paths.js path validation, vscode://file encoding
256
290
  lib/host/launch.js VS Code / Explorer launching
257
- lib/host/route.js /open route and HTTP status codes
291
+ lib/host/route.js /open and /session/delete routes, HTTP status codes
292
+ lib/host/session-delete.js transcript verification and deletion (detach / rm / re-check)
258
293
  lib/client.js browser half: fiber lookup, slot registration, menu mount
259
294
  cordis.patch.yml bundle patch inserting the plugin into the profile tree
260
295
  scripts/install.ps1 pnpm-free install / uninstall
@@ -288,7 +323,7 @@ party cannot re-layout someone else's slot.
288
323
 
289
324
  Therefore a session right-click does exactly one thing: find the `Menu` in the
290
325
  row's fiber subtree and trigger its anchor (the ellipsis button). The same slot
291
- content opens. The plugin's own three actions are registered through
326
+ content opens. The plugin's own actions are registered through
292
327
  `ctx.slots.inject` + `ctx.slots.register`, so:
293
328
 
294
329
  - they do not depend on built-in fork/pin entries existing;
@@ -296,6 +331,9 @@ content opens. The plugin's own three actions are registered through
296
331
  - no built-in action is copied or hardcoded.
297
332
 
298
333
  Workspace rows have no such slot, so their menu is still composed by this plugin.
334
+ The official `Menu` accepts only a flat `items` list and cannot express submenus, so
335
+ the workspace menu is drawn with `MenuSurface` + `MenuItemButton`: rows, icons,
336
+ danger styling and separators reuse the official controls.
299
337
 
300
338
  ### Why the session menu appears at the pointer
301
339
 
@@ -308,15 +346,15 @@ position.
308
346
 
309
347
  The "…" menu and the right-click menu share one `Menu` instance and one slot
310
348
  content; the only difference is the `rightClickMenuUntil` window — the plugin's
311
- three entries mount only inside it, and the window is cleared when the menu closes.
349
+ entries mount only inside it, and the window is cleared when the menu closes.
312
350
 
313
351
  ### Why the workspace menu is mounted imperatively
314
352
 
315
353
  A contextmenu event is not part of React's render flow. The workspace menu creates
316
- a `0×0`, `z-index:2147483647` host on demand, `createRoot`s the official `Menu`
317
- (`portal` plus an explicit `getAnchorRect` pinned to the pointer), and unmounts and
318
- removes the host on close. The session menu mounts nothing new; it only opens the
319
- row's existing menu.
354
+ a `0×0`, `z-index:2147483647` host on demand and `createRoot`s a self-drawn panel;
355
+ after mount it measures once and clamps its corner into the viewport, then unmounts
356
+ and removes the host on close. The session menu mounts nothing new; it only opens
357
+ the row's existing menu.
320
358
 
321
359
  ### Host route
322
360
 
@@ -333,6 +371,23 @@ row's existing menu.
333
371
  - spawn uses `detached + stdio:'ignore'` and deliberately does **not** set
334
372
  `windowsHide` (otherwise Explorer windows would be hidden).
335
373
 
374
+ `POST /dsh-sidebar-row-menu/session/delete`, body `{ sessionIds: string[] }`.
375
+
376
+ - same loopback / POST / exact path / 64 KB body checks; `sessionIds` must be a
377
+ non-empty array of non-empty strings, at most 500;
378
+ - sequential deletion: cancel a running session, detach a live one, then locate the
379
+ transcript directory through `sessionPersistence.locate()`; the directory's
380
+ basename must equal the session id or deletion is refused (no parent-directory
381
+ misfires);
382
+ - after deleting, the directory is re-checked three times to ensure it did not come
383
+ back, then the `workspaceRegistry` archive/pin records are cleared and
384
+ `api-session/removed` is emitted;
385
+ - partial failures return `200` + `{ ok:false, deleted, failed, error }`; the dialog
386
+ stays open and reports the counts.
387
+
388
+ "Open with" does not touch this plugin's host: it calls DSH's built-in
389
+ `open-in-app/apps`, `open-in-app/open` and `open-in-app/icon/<id>` directly.
390
+
336
391
  ## Compatibility
337
392
 
338
393
  Built against DSH client `0.2.1-rc.5` (`ProjectRowItem`, `SessionNodeItem`,
@@ -348,16 +403,19 @@ Built against DSH client `0.2.1-rc.5` (`ProjectRowItem`, `SessionNodeItem`,
348
403
  - Session right-click depends on the row's `Menu` staying in the fiber subtree. If
349
404
  it is not found, the plugin clicks the row-actions ellipsis button; failing that
350
405
  it gives up — it never builds a competing menu and never triggers row open.
351
- - Session "delete" is not offered: DSH officially supports archive (recoverable).
352
- Deleting records by force tends to leave orphan data. Archive/unarchive is
353
- handled by the built-in menu entry.
354
- - The VS Code / Explorer directory for a session comes from `sessions.list`'s
355
- `cwd`, falling back to the workspace directory. Ungrouped sessions may have no
406
+ - Permanent deletion is offered for **archived** sessions only; unarchived sessions
407
+ still use the built-in archive/unarchive. Deletion does not cascade into forked
408
+ child sessions — delete those separately when needed.
409
+ - Deletion works directly on the transcript directory; the host has no trash bin.
410
+ The confirmation dialog states that it cannot be undone.
411
+ - The open-with directory for a session comes from `sessions.list`'s `cwd`,
412
+ falling back to the workspace directory. Ungrouped sessions may have no
356
413
  directory; in that case a "no directory available" toast is shown.
357
414
 
358
415
  ## License and notices
359
416
 
360
417
  - Code: [MIT](LICENSE).
418
+ - Changelog: [CHANGELOG.md](CHANGELOG.md).
361
419
  - Third-party code and full license texts: [NOTICE.md](NOTICE.md) · [English](NOTICE.en.md).
362
420
  - AI usage and code provenance: [AI_USAGE.md](AI_USAGE.md) · [English](AI_USAGE.en.md).
363
421
 
package/README.md CHANGED
@@ -12,12 +12,13 @@
12
12
  - **工作区行**:右键弹出菜单(复刻 `dsh-sidebar-context-menu` 的能力);
13
13
  - **工作区下层的会话行**:右键在指针处展开该行内置的「…」菜单,并追加本插件的条目。
14
14
 
15
- 菜单使用 DSH 官方的 `Menu` 组件渲染,视觉、定位、键盘导航和“点外部关闭”都与内置
16
- 「…」菜单一致。工作区菜单由本插件组项;会话菜单的内容来自
15
+ 工作区菜单用 DSH 官方的 `MenuSurface` + `MenuItemButton` 自绘(官方 `Menu` 的条目不支持
16
+ 子菜单),视觉、行高、图标、危险色与分组分隔线都复用官方控件,键盘导航和“点外部关闭”
17
+ 与内置菜单一致。会话菜单的内容来自
17
18
  `sidebar.workspaces.session.menu.item` slot —— 内置动作和其他插件的动作都在里面,
18
19
  本插件只追加自己的条目,不复制、不硬编码任何内置动作。
19
20
 
20
- > 点行尾「…」按钮看到的菜单保持 DSH 原样;本插件自己的三个条目只在右键展开时出现。
21
+ > 点行尾「…」按钮看到的菜单保持 DSH 原样;本插件自己的条目只在右键展开时出现。
21
22
  > 右键展开的菜单不会因为鼠标移出而关闭(与工作区右键一致),只有点击外部、选中条目或按 Esc 才关闭。
22
23
 
23
24
  ## 功能
@@ -28,8 +29,8 @@
28
29
  | --- | --- |
29
30
  | 新会话 | 展开该工作区并新建会话(等价于行尾 `+`) |
30
31
  | 重命名 | 打开官方“重命名工作区”对话框 |
31
- | 使用 VS Code 打开 | 宿主在新窗口打开该工作区目录 |
32
- | 在资源管理器中打开 | 宿主打开系统文件管理器 |
32
+ | 置顶的打开方式 | 被置顶的应用直接显示在一级菜单(例如「用 Visual Studio Code 打开」),点击后用该应用打开工作区目录 |
33
+ | 打开方式 | 二级菜单列出宿主提供的外部应用(编辑器、终端、文件管理器);与会话菜单共用同一套应用列表、置顶与开关设置,鼠标悬浮自动展开 |
33
34
  | 复制工作区路径 | 复制目录路径到剪贴板 |
34
35
  | 在新标签中打开 | 仅在装有 `dsh-project-tabs`(暴露 `openWorkspaceInTab`)时出现 |
35
36
  | 删除工作区 | 打开官方删除确认对话框 |
@@ -42,22 +43,51 @@
42
43
  | --- | --- |
43
44
  | DSH 内置 | 重命名、分叉会话、置顶 / 取消置顶、归档 / 取消归档、复制 Session ID |
44
45
  | 其他插件 | 它们注册进 `sidebar.workspaces.session.menu.item` 的条目 |
45
- | 本插件 | 使用 VS Code 打开、在资源管理器中打开、复制会话链接 |
46
+ | 本插件 | 置顶的打开方式(一级)、打开方式(二级菜单)、永久删除会话 / 删除所有已归档会话(仅已归档会话显示) |
46
47
 
47
- 本插件追加的三个条目:
48
+ 本插件追加的条目:
48
49
 
49
50
  | 菜单项 | 行为 |
50
51
  | --- | --- |
51
- | 使用 VS Code 打开 | 优先用会话自己的 `cwd`,取不到则用所属工作区目录 |
52
- | 在资源管理器中打开 | 同上 |
53
- | 复制会话链接 | 复制 `?session=<id>` 深链接 |
52
+ | 打开方式 | 二级菜单列出宿主提供的外部应用(编辑器、终端、文件管理器),用会话自己的 `cwd` 打开;取不到时退回所属工作区目录 |
53
+ | 置顶的打开方式 | 被置顶的应用直接显示在一级菜单(例如「用 Visual Studio Code 打开」);未配置时自动置顶检测到的第一个编辑器,没有编辑器则置顶第一个应用。鼠标悬浮到「打开方式」会自动展开二级菜单 |
54
+ | 永久删除会话 | 只在已归档会话的右键菜单里出现;确认后永久删除这一个会话及其日志,不可恢复 |
55
+ | 删除所有已归档会话 | 只在已归档会话的右键菜单里出现;确认后永久删除全部已归档会话及其日志,不可恢复 |
54
56
 
55
- 这三条是**右键专属**:点行尾「…」按钮时它们不挂载。实现上使用一个只在右键展开瞬间
57
+ 「打开方式」的应用列表来自 DSH 内置的 `open-in-app` 路由,与 DSH 自己的「打开方式」
58
+ 能力同源;应用名和图标都由本插件展示,可在设置里逐个隐藏,也可以把常用应用置顶到
59
+ 一级菜单。两个删除入口由本插件自己的宿主路由完成,不会删除未归档会话,
60
+ 也不级联删除 fork 子会话。
61
+
62
+ 这些条目都是**右键专属**:点行尾「…」按钮时它们不挂载。实现上使用一个只在右键展开瞬间
56
63
  有效的窗口标记,窗口外的渲染直接返回 `null`。
57
64
 
58
65
  草稿会话(还没有任何消息的空白会话)没有内置「…」菜单,本插件同样不接管。
59
66
  非工作区 / 非会话的侧边栏行(如“显示更多”)也不会被拦截。
60
67
 
68
+ ### 设置
69
+
70
+ 设置 →「行菜单」里可以开关本插件的每个新增项:
71
+
72
+ | 开关 | 作用 |
73
+ | --- | --- |
74
+ | 打开方式 | 关闭后工作区 / 会话菜单里不再出现「打开方式」和置顶应用 |
75
+ | 打开方式 → 应用 | 逐个隐藏应用;旁边的「置顶」按钮把应用移到一级菜单 |
76
+ | 永久删除会话 | 关闭后已归档会话菜单里不再出现单条删除入口 |
77
+ | 删除所有已归档会话 | 关闭后不再出现批量删除入口 |
78
+
79
+ 开关存在浏览器 `localStorage`(`dsh.sidebar-row-menu.items.v1`、
80
+ `dsh.sidebar-row-menu.open-with.v1` 与 `dsh.sidebar-row-menu.open-with.pinned.v1`),
81
+ 改完立即生效,不需要重启。置顶项在第一次配置前是自动推导的:优先置顶检测到的第一个
82
+ 编辑器(通常是 VS Code),没有编辑器时置顶应用列表里的第一个。
83
+
84
+ ### 与 dsh-session-menu 共存
85
+
86
+ 同时安装 [`dsh-session-menu`](https://github.com/big-head-pigeon/dsh-session-menu) 时,
87
+ 本插件会在会话菜单 slot 里检测对方注册的 `session-menu-open-with` /
88
+ `session-menu-delete` / `session-menu-delete-archived`,命中后自动隐藏自己的同名条目,设置页对应开关置灰并
89
+ 提示“已由 dsh-session-menu 提供”。不会改动对方的配置,也不要求对方做任何适配。
90
+
61
91
  ## 安装
62
92
 
63
93
  要求:
@@ -82,13 +112,13 @@
82
112
  要固定版本,在包名后加版本号:
83
113
 
84
114
  ```
85
- dsh-sidebar-row-menu@1.3.4
115
+ dsh-sidebar-row-menu@1.4.0
86
116
  ```
87
117
 
88
118
  命令行等价写法:
89
119
 
90
120
  ```powershell
91
- dsh plugin --profile desktop add dsh-sidebar-row-menu@1.3.4
121
+ dsh plugin --profile desktop add dsh-sidebar-row-menu@1.4.0
92
122
  ```
93
123
 
94
124
  ### 从 GitHub 安装
@@ -108,13 +138,13 @@ DSH 桌面端通过 pnpm 安装 Git 依赖;本仓库的 `lib/` 已是可直接
108
138
  该地址跟随 `main` 的最新提交。要固定版本,在地址后加标签:
109
139
 
110
140
  ```
111
- https://github.com/TLEWA/dsh-sidebar-row-menu#v1.3.4
141
+ https://github.com/TLEWA/dsh-sidebar-row-menu#v1.4.0
112
142
  ```
113
143
 
114
144
  也可以直接安装 Actions 打出的压缩包(不经过 Git):
115
145
 
116
146
  ```
117
- https://github.com/TLEWA/dsh-sidebar-row-menu/releases/download/v1.3.4/dsh-sidebar-row-menu-1.3.4.tgz
147
+ https://github.com/TLEWA/dsh-sidebar-row-menu/releases/download/v1.4.0/dsh-sidebar-row-menu-1.4.0.tgz
118
148
  ```
119
149
 
120
150
  命令行等价写法:
@@ -219,7 +249,7 @@ npm run build # npm pack(prepack 会先跑 check),产出 .tgz
219
249
  测试覆盖宿主侧纯函数(路径校验、`vscode://file` 编码、loopback 判定、路由状态码)
220
250
  和客户端模块(模块 id、导出、依赖白名单、监听器安装/卸载、slot 注册表),并用伪造的
221
251
  `__reactFiber$`、DOM 与 `Menu` 宿主做集成测试:工作区右键的菜单项顺序、会话右键是否
222
- 展开内置菜单而不是自建菜单、草稿行是否被放过、复制链接的剪贴板内容都在断言里。
252
+ 展开内置菜单而不是自建菜单、草稿行是否被放过、复制工作区路径的 Toast 反馈都在断言里。
223
253
  真实 fiber 与服务仍需在运行中的 GUI 里做人工验证。
224
254
 
225
255
  目录:
@@ -229,7 +259,8 @@ lib/index.js 宿主入口:name / inject / apply,再导出可测试
229
259
  lib/host/security.js loopback 请求围栏
230
260
  lib/host/paths.js 路径校验、vscode://file 编码
231
261
  lib/host/launch.js VS Code / 资源管理器启动
232
- lib/host/route.js /open 路由与 HTTP 状态码
262
+ lib/host/route.js /open 与 /session/delete 路由、HTTP 状态码
263
+ lib/host/session-delete.js 会话日志目录的校验与删除(detach / rm / 复查)
233
264
  lib/client.js 客户端半边:fiber 解析、slot 注册、菜单挂载
234
265
  cordis.patch.yml bundle patch:把插件插进 profile 插件树
235
266
  scripts/install.ps1 无 pnpm 的安装 / 卸载脚本
@@ -258,14 +289,16 @@ test/*.test.mjs node:test
258
289
  每个条目只能渲染自己声明过的子 slot,第三方无法直接把手伸进别人的 slot 重新排版。
259
290
 
260
291
  因此会话行右键只做一件事:在行组件的 fiber 子树里找到那个 `Menu`,触发它 anchor
261
- (省略号按钮)的点击,展开的自然是同一份 slot 内容。本插件自己的三个动作也通过
292
+ (省略号按钮)的点击,展开的自然是同一份 slot 内容。本插件自己的动作也通过
262
293
  `ctx.slots.inject` + `ctx.slots.register` 注册进去,所以:
263
294
 
264
295
  - 不依赖「分叉」「置顶」这些内置条目是否存在;
265
296
  - 内置或别的插件以后新增条目,右键菜单自动出现;
266
297
  - 不复制、不硬编码任何内置动作。
267
298
 
268
- 工作区行没有这样的 slot,所以工作区菜单仍由本插件自己组项。
299
+ 工作区行没有这样的 slot,所以工作区菜单仍由本插件自己组项。官方 `Menu` 的
300
+ `items` 只支持单层条目,无法表达子菜单,因此工作区菜单用 `MenuSurface` +
301
+ `MenuItemButton` 自绘:行、图标、危险色和分隔线都复用官方控件,交互与官方菜单一致。
269
302
 
270
303
  ### 为什么会话菜单能贴着鼠标
271
304
 
@@ -275,13 +308,13 @@ test/*.test.mjs node:test
275
308
  方法,不影响按钮菜单的默认位置。
276
309
 
277
310
  「…」按钮菜单与右键菜单共用同一个 `Menu` 实例和同一份 slot 内容,区别只在
278
- `rightClickMenuUntil` 窗口:本插件三条只在窗口内挂载,窗口随菜单关闭一并清零。
311
+ `rightClickMenuUntil` 窗口:本插件条目只在窗口内挂载,窗口随菜单关闭一并清零。
279
312
 
280
313
  ### 为什么菜单是命令式挂载
281
314
 
282
315
  右键事件不是 React 渲染流的一部分。工作区菜单按需创建一个 `0×0`、
283
- `z-index:2147483647` 的容器,`createRoot` 渲染官方 `Menu`(`portal` + 显式
284
- `getAnchorRect` 钉在鼠标位置),关闭时 `unmount()` 并移除容器。会话菜单不挂载任何
316
+ `z-index:2147483647` 的容器,`createRoot` 渲染自绘面板;面板挂载后量一次尺寸,
317
+ 再把左上角夹进视口,避免贴边时被裁掉。关闭时 `unmount()` 并移除容器。会话菜单不挂载任何
285
318
  新容器,只是打开行内已有的官方菜单。
286
319
 
287
320
  ### 宿主路由
@@ -297,6 +330,19 @@ test/*.test.mjs node:test
297
330
  都找不到时退回 `rundll32` 打开 `vscode://file/...`;
298
331
  - spawn 用 `detached + stdio:'ignore'`,不设 `windowsHide`(否则资源管理器窗口会被隐藏)。
299
332
 
333
+ `POST /dsh-sidebar-row-menu/session/delete`,body `{ sessionIds: string[] }`。
334
+
335
+ - 同样的 loopback / POST / 路径 / 64 KB body 校验;`sessionIds` 必须是非空字符串数组,
336
+ 最多 500 个;
337
+ - 串行删除:先取消运行中的会话、detach 活会话,再按 `sessionPersistence.locate()` 找到
338
+ 会话目录;目录 basename 必须与会话 id 完全一致,否则拒绝删除(防误删父目录);
339
+ - 删除后 3 次复查目录没有复活,再清理 `workspaceRegistry` 的归档 / 置顶记录并发出
340
+ `api-session/removed`;
341
+ - 部分失败返回 `200` + `{ ok:false, deleted, failed, error }`,前端保留对话框并显示计数。
342
+
343
+ 「打开方式」不经过本插件宿主:直接调用 DSH 内置的 `open-in-app/apps`、
344
+ `open-in-app/open`、`open-in-app/icon/<id>`。
345
+
300
346
  ## 兼容性
301
347
 
302
348
  按 DSH 客户端 `0.2.1-rc.5` 的 `ProjectRowItem` / `SessionNodeItem` / `Menu` 实现。
@@ -310,14 +356,16 @@ DSH 升级若改动行组件或菜单定位实现:
310
356
  - 依赖 DSH 内置行组件的 props 形状。DSH 升级若改了这两个组件,右键会静默不弹。
311
357
  - 会话右键依赖行内 `Menu` 组件仍在 fiber 子树里。找不到时退回点击行内操作区的
312
358
  省略号按钮,再找不到就放弃 —— 不会自建菜单,也不会误触行的打开动作。
313
- - 本插件不提供会话“删除”:DSH 官方只支持归档,归档后可恢复;强行删记录容易留下
314
- 孤儿数据。会话的归档 / 取消归档由内置菜单条目负责。
315
- - 会话行右键的 VS Code / 资源管理器目录来自 `sessions.list` 的 `cwd`,取不到时退回
359
+ - 永久删除只对**已归档**会话开放;未归档会话仍只能用内置的归档 / 取消归档。删除不会
360
+ 级联删除 fork 出来的子会话,需要时请分别删除。
361
+ - 删除操作直接作用于会话日志目录,宿主没有回收站;确认框里已明确提示不可恢复。
362
+ - 会话行「打开方式」的目录来自 `sessions.list` 的 `cwd`,取不到时退回
316
363
  所属工作区目录;未分组会话可能没有目录,此时会提示“没有可用的目录路径”。
317
364
 
318
365
  ## 许可与声明
319
366
 
320
367
  - 代码:[MIT](LICENSE)。
368
+ - 更新日志:[CHANGELOG.md](CHANGELOG.md)。
321
369
  - 第三方代码引用与许可证全文:[NOTICE.md](NOTICE.md) · [English](NOTICE.en.md)。
322
370
  - AI 使用与代码来源声明:[AI_USAGE.md](AI_USAGE.md) · [English](AI_USAGE.en.md)。
323
371