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