dsh-sidebar-row-menu 1.4.0 → 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 CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
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
+
3
18
  ## 1.4.0 — 2026-11-03
4
19
 
5
20
  ### Added
package/README.en.md CHANGED
@@ -49,7 +49,7 @@ Right-click does not build a second menu; it opens the row's own "…" menu:
49
49
  | --- | --- |
50
50
  | DSH built-ins | Rename, Fork session, Pin / Unpin, Archive / Unarchive, Copy Session ID |
51
51
  | Other plugins | Whatever they register into `sidebar.workspaces.session.menu.item` |
52
- | This plugin | Pinned open-with apps (top level), Open with (submenu), Delete session / Delete all archived sessions (archived rows only) |
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) |
53
53
 
54
54
  The entries added by this plugin:
55
55
 
@@ -57,14 +57,15 @@ The entries added by this plugin:
57
57
  | --- | --- |
58
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
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 |
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
61
  | Delete all archived sessions | Only on archived sessions; permanently deletes every archived session and its transcript after confirmation |
62
62
 
63
63
  The "Open with" catalog comes from DSH's built-in `open-in-app` routes, so it is the
64
64
  same source DSH itself uses; labels and icons are rendered by this plugin, each app
65
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.
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.
68
69
 
69
70
  These entries are **right-click only**: they do not mount when the "…" button opens
70
71
  the menu. A short-lived window flag is set before opening; outside that window the
@@ -81,7 +82,8 @@ Settings → "Row menu" toggles every new entry:
81
82
  | --- | --- |
82
83
  | Open with | Hides "Open with" and every pinned app from workspace and session menus |
83
84
  | 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 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 |
85
87
  | Delete all archived sessions | Hides the bulk-delete entry |
86
88
 
87
89
  Switches live in browser `localStorage` (`dsh.sidebar-row-menu.items.v1`,
@@ -124,13 +126,13 @@ resolve it directly by name:
124
126
  Pin a version by appending it to the name:
125
127
 
126
128
  ```
127
- dsh-sidebar-row-menu@1.4.0
129
+ dsh-sidebar-row-menu@1.4.1
128
130
  ```
129
131
 
130
132
  Equivalent command line:
131
133
 
132
134
  ```powershell
133
- dsh plugin --profile desktop add dsh-sidebar-row-menu@1.4.0
135
+ dsh plugin --profile desktop add dsh-sidebar-row-menu@1.4.1
134
136
  ```
135
137
 
136
138
  ### Install from GitHub
@@ -150,13 +152,13 @@ repository is already runnable, so **no local build is required**.
150
152
  That URL tracks the latest commit on `main`. Pin a tag for a stable version:
151
153
 
152
154
  ```
153
- https://github.com/TLEWA/dsh-sidebar-row-menu#v1.4.0
155
+ https://github.com/TLEWA/dsh-sidebar-row-menu#v1.4.1
154
156
  ```
155
157
 
156
158
  Or install the tarball built by Actions directly, without Git:
157
159
 
158
160
  ```
159
- https://github.com/TLEWA/dsh-sidebar-row-menu/releases/download/v1.4.0/dsh-sidebar-row-menu-1.4.0.tgz
161
+ https://github.com/TLEWA/dsh-sidebar-row-menu/releases/download/v1.4.1/dsh-sidebar-row-menu-1.4.1.tgz
160
162
  ```
161
163
 
162
164
  Equivalent command line:
@@ -403,9 +405,10 @@ Built against DSH client `0.2.1-rc.5` (`ProjectRowItem`, `SessionNodeItem`,
403
405
  - Session right-click depends on the row's `Menu` staying in the fiber subtree. If
404
406
  it is not found, the plugin clicks the row-actions ellipsis button; failing that
405
407
  it gives up — it never builds a competing menu and never triggers row open.
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.
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.
409
412
  - Deletion works directly on the transcript directory; the host has no trash bin.
410
413
  The confirmation dialog states that it cannot be undone.
411
414
  - The open-with directory for a session comes from `sessions.list`'s `cwd`,
package/README.md CHANGED
@@ -43,7 +43,7 @@
43
43
  | --- | --- |
44
44
  | DSH 内置 | 重命名、分叉会话、置顶 / 取消置顶、归档 / 取消归档、复制 Session ID |
45
45
  | 其他插件 | 它们注册进 `sidebar.workspaces.session.menu.item` 的条目 |
46
- | 本插件 | 置顶的打开方式(一级)、打开方式(二级菜单)、永久删除会话 / 删除所有已归档会话(仅已归档会话显示) |
46
+ | 本插件 | 置顶的打开方式(一级)、打开方式(二级菜单)、永久删除会话 / 删除所有已归档会话(默认仅已归档会话显示;可在设置里允许删除未归档会话) |
47
47
 
48
48
  本插件追加的条目:
49
49
 
@@ -51,13 +51,13 @@
51
51
  | --- | --- |
52
52
  | 打开方式 | 二级菜单列出宿主提供的外部应用(编辑器、终端、文件管理器),用会话自己的 `cwd` 打开;取不到时退回所属工作区目录 |
53
53
  | 置顶的打开方式 | 被置顶的应用直接显示在一级菜单(例如「用 Visual Studio Code 打开」);未配置时自动置顶检测到的第一个编辑器,没有编辑器则置顶第一个应用。鼠标悬浮到「打开方式」会自动展开二级菜单 |
54
- | 永久删除会话 | 只在已归档会话的右键菜单里出现;确认后永久删除这一个会话及其日志,不可恢复 |
54
+ | 永久删除会话 | 默认只在已归档会话的右键菜单里出现;确认后永久删除这一个会话及其日志,不可恢复。在设置里开启「允许删除未归档会话」后,未归档会话也会出现这一项 |
55
55
  | 删除所有已归档会话 | 只在已归档会话的右键菜单里出现;确认后永久删除全部已归档会话及其日志,不可恢复 |
56
56
 
57
57
  「打开方式」的应用列表来自 DSH 内置的 `open-in-app` 路由,与 DSH 自己的「打开方式」
58
58
  能力同源;应用名和图标都由本插件展示,可在设置里逐个隐藏,也可以把常用应用置顶到
59
- 一级菜单。两个删除入口由本插件自己的宿主路由完成,不会删除未归档会话,
60
- 也不级联删除 fork 子会话。
59
+ 一级菜单。两个删除入口由本插件自己的宿主路由完成,默认不会删除未归档会话;
60
+ 开启「允许删除未归档会话」后才会对普通会话开放。删除不会级联删除 fork 子会话。
61
61
 
62
62
  这些条目都是**右键专属**:点行尾「…」按钮时它们不挂载。实现上使用一个只在右键展开瞬间
63
63
  有效的窗口标记,窗口外的渲染直接返回 `null`。
@@ -73,7 +73,8 @@
73
73
  | --- | --- |
74
74
  | 打开方式 | 关闭后工作区 / 会话菜单里不再出现「打开方式」和置顶应用 |
75
75
  | 打开方式 → 应用 | 逐个隐藏应用;旁边的「置顶」按钮把应用移到一级菜单 |
76
- | 永久删除会话 | 关闭后已归档会话菜单里不再出现单条删除入口 |
76
+ | 永久删除会话 | 关闭后会话菜单里不再出现单条删除入口 |
77
+ | 允许删除未归档会话 | 默认关闭;开启后未归档会话的右键菜单也会出现「永久删除会话」,需先开启上一项 |
77
78
  | 删除所有已归档会话 | 关闭后不再出现批量删除入口 |
78
79
 
79
80
  开关存在浏览器 `localStorage`(`dsh.sidebar-row-menu.items.v1`、
@@ -112,13 +113,13 @@
112
113
  要固定版本,在包名后加版本号:
113
114
 
114
115
  ```
115
- dsh-sidebar-row-menu@1.4.0
116
+ dsh-sidebar-row-menu@1.4.1
116
117
  ```
117
118
 
118
119
  命令行等价写法:
119
120
 
120
121
  ```powershell
121
- dsh plugin --profile desktop add dsh-sidebar-row-menu@1.4.0
122
+ dsh plugin --profile desktop add dsh-sidebar-row-menu@1.4.1
122
123
  ```
123
124
 
124
125
  ### 从 GitHub 安装
@@ -138,13 +139,13 @@ DSH 桌面端通过 pnpm 安装 Git 依赖;本仓库的 `lib/` 已是可直接
138
139
  该地址跟随 `main` 的最新提交。要固定版本,在地址后加标签:
139
140
 
140
141
  ```
141
- https://github.com/TLEWA/dsh-sidebar-row-menu#v1.4.0
142
+ https://github.com/TLEWA/dsh-sidebar-row-menu#v1.4.1
142
143
  ```
143
144
 
144
145
  也可以直接安装 Actions 打出的压缩包(不经过 Git):
145
146
 
146
147
  ```
147
- https://github.com/TLEWA/dsh-sidebar-row-menu/releases/download/v1.4.0/dsh-sidebar-row-menu-1.4.0.tgz
148
+ https://github.com/TLEWA/dsh-sidebar-row-menu/releases/download/v1.4.1/dsh-sidebar-row-menu-1.4.1.tgz
148
149
  ```
149
150
 
150
151
  命令行等价写法:
@@ -356,8 +357,8 @@ DSH 升级若改动行组件或菜单定位实现:
356
357
  - 依赖 DSH 内置行组件的 props 形状。DSH 升级若改了这两个组件,右键会静默不弹。
357
358
  - 会话右键依赖行内 `Menu` 组件仍在 fiber 子树里。找不到时退回点击行内操作区的
358
359
  省略号按钮,再找不到就放弃 —— 不会自建菜单,也不会误触行的打开动作。
359
- - 永久删除只对**已归档**会话开放;未归档会话仍只能用内置的归档 / 取消归档。删除不会
360
- 级联删除 fork 出来的子会话,需要时请分别删除。
360
+ - 永久删除默认只对**已归档**会话开放;在设置里开启「允许删除未归档会话」后,未归档
361
+ 会话也能从右键菜单直接删除。删除不会级联删除 fork 出来的子会话,需要时请分别删除。
361
362
  - 删除操作直接作用于会话日志目录,宿主没有回收站;确认框里已明确提示不可恢复。
362
363
  - 会话行「打开方式」的目录来自 `sessions.list` 的 `cwd`,取不到时退回
363
364
  所属工作区目录;未分组会话可能没有目录,此时会提示“没有可用的目录路径”。
package/lib/client.js CHANGED
@@ -88,7 +88,7 @@ window.__ModuleLoader__.load({
88
88
  if (children.length === 0) return jsx(type, props);
89
89
  return jsx(type, { ...props, children: children.length === 1 ? children[0] : children });
90
90
  }
91
- /** 永久删除会话的宿主端点(只允许删除已归档会话,见本文件条目)。 */
91
+ /** 永久删除会话的宿主端点;是否对未归档会话开放由本地开关决定。 */
92
92
  const DELETE_ENDPOINT = '/dsh-sidebar-row-menu/session/delete';
93
93
  /** 官方 open-in-app 的三条路由;用文档相对路径让浏览器自带认证。 */
94
94
  const APPS_ROUTE = 'open-in-app/apps';
@@ -104,7 +104,17 @@ window.__ModuleLoader__.load({
104
104
  'intellij', 'pycharm', 'webstorm', 'phpstorm', 'goland', 'rider', 'rustrover',
105
105
  'androidstudio', 'xcode',
106
106
  ];
107
- const ITEM_KEYS = ['openWith', 'deleteSession', 'deleteArchived'];
107
+ /**
108
+ * 各项菜单开关的默认值。删除未归档会话是破坏性能力,默认关闭,
109
+ * 必须在设置里主动开启后才出现在普通会话的右键菜单里。
110
+ */
111
+ const ITEM_DEFAULTS = {
112
+ openWith: true,
113
+ deleteSession: true,
114
+ deleteArchived: true,
115
+ deleteUnarchived: false,
116
+ };
117
+ const ITEM_KEYS = Object.keys(ITEM_DEFAULTS);
108
118
  /**
109
119
  * dsh-session-menu 注册的同一能力条目 id。检测到对方存在时,本插件对应项
110
120
  * 自动隐藏,避免同一份菜单里出现两条一模一样的动作。
@@ -138,9 +148,11 @@ window.__ModuleLoader__.load({
138
148
  'settings.openWith.label': '打开方式',
139
149
  'settings.openWith.hint': '在子菜单里选择编辑器、终端或文件管理器打开工作区或会话目录;置顶的应用直接显示在菜单一级。',
140
150
  'settings.deleteSession.label': '永久删除会话',
141
- 'settings.deleteSession.hint': '在已归档会话的菜单里永久删除这一个会话及其日志。',
151
+ 'settings.deleteSession.hint': '在会话菜单里永久删除这一个会话及其日志;默认只对已归档会话显示。',
142
152
  'settings.deleteArchived.label': '删除所有已归档会话',
143
153
  'settings.deleteArchived.hint': '在已归档会话的菜单里一次清理全部归档会话。',
154
+ 'settings.deleteUnarchived.label': '允许删除未归档会话',
155
+ 'settings.deleteUnarchived.hint': '开启后,未归档会话的右键菜单也会出现「永久删除会话」;确认后日志立即从磁盘移除,不可恢复。',
144
156
  'settings.children': '选择要显示的应用',
145
157
  'settings.pin': '置顶',
146
158
  'settings.pinned': '已置顶',
@@ -190,9 +202,11 @@ window.__ModuleLoader__.load({
190
202
  'settings.openWith.label': 'Open with',
191
203
  'settings.openWith.hint': 'Pick an editor, terminal or file manager for workspace or session directories; pinned apps show up directly in the menu.',
192
204
  'settings.deleteSession.label': 'Delete session permanently',
193
- 'settings.deleteSession.hint': 'Permanently delete a single archived session and its transcript from an archived row.',
205
+ 'settings.deleteSession.hint': 'Permanently delete one session and its transcript from its menu; shown on archived sessions by default.',
194
206
  'settings.deleteArchived.label': 'Delete all archived sessions',
195
207
  'settings.deleteArchived.hint': 'Clean up every archived session from an archived session row.',
208
+ 'settings.deleteUnarchived.label': 'Allow deleting unarchived sessions',
209
+ 'settings.deleteUnarchived.hint': 'Also show "Delete session permanently" on unarchived rows. The transcript is removed from disk immediately and cannot be restored.',
196
210
  'settings.children': 'Applications to show',
197
211
  'settings.pin': 'Pin',
198
212
  'settings.pinned': 'Pinned',
@@ -487,8 +501,7 @@ window.__ModuleLoader__.load({
487
501
  /* ------------------------------------------------ 菜单项设置(localStorage) */
488
502
 
489
503
  function readStoredItems() {
490
- const defaults = {};
491
- for (const key of ITEM_KEYS) defaults[key] = true;
504
+ const defaults = { ...ITEM_DEFAULTS };
492
505
  try {
493
506
  const raw = globalThis.localStorage?.getItem(ITEMS_KEY);
494
507
  if (typeof raw !== 'string' || raw === '') return defaults;
@@ -543,7 +556,7 @@ window.__ModuleLoader__.load({
543
556
  }
544
557
 
545
558
  function itemOn(key) {
546
- return itemSettings[key] !== false;
559
+ return itemSettings[key] ?? ITEM_DEFAULTS[key] ?? false;
547
560
  }
548
561
 
549
562
  /* ------------------------------------- 打开方式:应用列表与二级开关 */
@@ -1206,8 +1219,8 @@ window.__ModuleLoader__.load({
1206
1219
  }
1207
1220
 
1208
1221
  /**
1209
- * 会话条目「永久删除会话」:只在已归档会话的菜单里显示;和 dsh-session-menu
1210
- * 的同名功能二选一。
1222
+ * 会话条目「永久删除会话」:已归档会话默认可见;未归档会话要先在设置里
1223
+ * 打开「允许删除未归档会话」。和 dsh-session-menu 的同名功能二选一。
1211
1224
  */
1212
1225
  function SessionDeleteMenuItem({ sessionId, displayTitle, useMenuOpenState, t }) {
1213
1226
  const visible = useRightClickEntry();
@@ -1215,7 +1228,7 @@ window.__ModuleLoader__.load({
1215
1228
  const archived = useArchivedIds();
1216
1229
  const setMenuOpen = menuCloser(useMenuOpenState);
1217
1230
  if (!visible || items.deleteSession === false || takenOver('deleteSession')) return null;
1218
- if (!archived.has(sessionId)) return null;
1231
+ if (!archived.has(sessionId) && items.deleteUnarchived !== true) return null;
1219
1232
  return jsx(MenuItemButton, {
1220
1233
  danger: true,
1221
1234
  separatorBefore: true,
@@ -1258,6 +1271,7 @@ window.__ModuleLoader__.load({
1258
1271
  const SETTINGS_ROWS = [
1259
1272
  ['openWith', 'settings.openWith.label', 'settings.openWith.hint'],
1260
1273
  ['deleteSession', 'settings.deleteSession.label', 'settings.deleteSession.hint'],
1274
+ ['deleteUnarchived', 'settings.deleteUnarchived.label', 'settings.deleteUnarchived.hint'],
1261
1275
  ['deleteArchived', 'settings.deleteArchived.label', 'settings.deleteArchived.hint'],
1262
1276
  ];
1263
1277
 
@@ -1309,6 +1323,9 @@ window.__ModuleLoader__.load({
1309
1323
 
1310
1324
  // 应用开关必须紧跟「打开方式」这一行,而不是落到整个列表末尾。
1311
1325
  const rows = SETTINGS_ROWS.flatMap(([key, labelKey, hintKey]) => {
1326
+ // 「允许删除未归档会话」依赖「永久删除会话」这条主开关。
1327
+ const lockedByParent = key === 'deleteUnarchived'
1328
+ && (items.deleteSession === false || takenOver('deleteSession'));
1312
1329
  const row = h('div', { className: 'dsrm-settings-row', key },
1313
1330
  h('div', { className: 'dsrm-settings-copy' },
1314
1331
  h('div', { className: 'dsrm-settings-label' }, t(labelKey)),
@@ -1316,9 +1333,12 @@ window.__ModuleLoader__.load({
1316
1333
  ),
1317
1334
  h('div', { className: 'dsrm-settings-controls' },
1318
1335
  jsx(Switch, {
1319
- checked: items[key] !== false,
1320
- disabled: takenOver(key),
1336
+ checked: items[key] === true,
1337
+ disabled: takenOver(key) || lockedByParent,
1321
1338
  label: t(labelKey),
1339
+ title: lockedByParent
1340
+ ? t('settings.childLocked', { name: t('settings.deleteSession.label') })
1341
+ : undefined,
1322
1342
  onChange: (next) => setItem(key, next),
1323
1343
  }),
1324
1344
  key === 'openWith'
@@ -1586,7 +1606,7 @@ window.__ModuleLoader__.load({
1586
1606
  /**
1587
1607
  * 会话菜单条目:
1588
1608
  * - 置顶应用 + 「打开方式」子菜单(官方 open-in-app 路由)
1589
- * - 「永久删除会话」「删除所有已归档会话」(仅已归档会话显示)
1609
+ * - 「永久删除会话」「删除所有已归档会话」(已归档会话显示;未归档会话需在设置里开启)
1590
1610
  * 目录从客户端服务里现取 —— 这样不依赖行组件的内部闭包。
1591
1611
  */
1592
1612
  function registerSessionMenu(ctx) {
package/lib/host/route.js CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * 浏览器端不能自己打开系统应用,也不该直接碰会话日志,所以这两件事都放在 host:
5
5
  * POST /dsh-sidebar-row-menu/open 打开目录(VS Code / 资源管理器)
6
- * POST /dsh-sidebar-row-menu/session/delete 永久删除会话(仅已归档,由 UI 把关)
6
+ * POST /dsh-sidebar-row-menu/session/delete 永久删除会话(归档范围由 UI 把关)
7
7
  */
8
8
 
9
9
  import { inspectOpenPath } from './paths.js';
package/lib/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * 两件事:
5
5
  * 1. `/open` 让浏览器请宿主用系统命令打开目录;
6
- * 2. `/session/delete` 永久删除会话日志(仅 UI 对已归档会话开放)。
6
+ * 2. `/session/delete` 永久删除会话日志(默认由 UI 对已归档会话开放;
7
7
  *
8
8
  * 具体实现拆成四个模块:
9
9
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-sidebar-row-menu",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
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, with open-with and archived-session cleanup.",
6
6
  "keywords": [