dsh-delete-session 0.1.1 → 0.1.3
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/README.md +4 -0
- package/README.zh.md +1 -0
- package/package.json +1 -1
- package/src/client.js +61 -19
package/README.md
CHANGED
|
@@ -16,6 +16,10 @@ Built for DeepSeek Harness (DSH) Web, tested on `0.1.5-rc.1`.
|
|
|
16
16
|
action always targets the row you clicked).
|
|
17
17
|
- **Risk-consent dialog**: shows the session title and id; the confirm button
|
|
18
18
|
stays disabled until the acknowledgement checkbox is ticked.
|
|
19
|
+
- **Confirm once, then skip**: tick "Don't ask again" in the dialog and later
|
|
20
|
+
deletes run directly from the menu (a toast reports the result). Hold Shift
|
|
21
|
+
while clicking to force the dialog again, or clear
|
|
22
|
+
`localStorage['dsh-delete-session:skip-confirm']` to restore it permanently.
|
|
19
23
|
- **Real deletion**: stops a running agent (cancel + quiescence), flushes and
|
|
20
24
|
detaches the live session, removes every on-disk session directory (both the
|
|
21
25
|
raw and `session-` prefixed id), verifies through the persistence service,
|
package/README.zh.md
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
- **侧边栏会话菜单里的「删除会话」**:无需切换会话(会话 ID 从菜单的 React fiber 读取,
|
|
14
14
|
永远作用于你点击的那一行)。
|
|
15
15
|
- **风险确认对话框**:显示会话标题与 ID;勾选「我已了解,永久删除」前确认按钮不可用。
|
|
16
|
+
- **确认一次后可跳过弹窗**:在对话框里勾选「不再询问,以后直接删除」,之后点菜单项会直接删除(结果以 toast 提示);按住 Shift 点击可临时强制弹窗;清除 `localStorage['dsh-delete-session:skip-confirm']` 可永久恢复弹窗。
|
|
16
17
|
- **真正的删除**:停止运行中的 agent(cancel + 等待空闲)、flush 并 detach 活跃会话、
|
|
17
18
|
删除磁盘上的全部会话目录(原始 ID 与 `session-` 前缀两种写法)、经持久化服务复核,
|
|
18
19
|
最后从工作区记账中移除,避免侧栏残留「未分组」孤儿。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-delete-session",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Delete sessions from the DSH Web sidebar: adds a Delete action to the session row menu with a risk-consent dialog, then removes the session log, workspace accounting and live session state.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/client.js
CHANGED
|
@@ -27,6 +27,7 @@ window.__ModuleLoader__.load({
|
|
|
27
27
|
confirm: '删除',
|
|
28
28
|
deleting: '删除中…',
|
|
29
29
|
ack: '我已了解,永久删除',
|
|
30
|
+
dontAsk: '不再询问,以后直接删除',
|
|
30
31
|
done: '已删除会话',
|
|
31
32
|
failed: '删除失败:',
|
|
32
33
|
busy: '该会话正被 DSH 打开,暂时无法删除;请重启 DSH 后再试。',
|
|
@@ -42,6 +43,7 @@ window.__ModuleLoader__.load({
|
|
|
42
43
|
confirm: 'Delete',
|
|
43
44
|
deleting: 'Deleting...',
|
|
44
45
|
ack: 'I understand - delete permanently',
|
|
46
|
+
dontAsk: "Don't ask again",
|
|
45
47
|
done: 'Session deleted',
|
|
46
48
|
failed: 'Delete failed: ',
|
|
47
49
|
busy: 'This session is currently open in DSH and cannot be deleted yet. Restart DSH and try again.',
|
|
@@ -52,6 +54,49 @@ window.__ModuleLoader__.load({
|
|
|
52
54
|
let localeSvc = null
|
|
53
55
|
let sessionsSvc = null
|
|
54
56
|
|
|
57
|
+
// Once the user ticks "don't ask again" the confirmation dialog is
|
|
58
|
+
// skipped and the menu item deletes directly. Shift+click always opens
|
|
59
|
+
// the dialog again, and clearing the key in localStorage restores it.
|
|
60
|
+
const SKIP_KEY = 'dsh-delete-session:skip-confirm'
|
|
61
|
+
|
|
62
|
+
function skipConfirm() {
|
|
63
|
+
try { return localStorage.getItem(SKIP_KEY) === '1' } catch { return false }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function setSkipConfirm() {
|
|
67
|
+
try { localStorage.setItem(SKIP_KEY, '1') } catch { /* private mode: ignore */ }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function postDelete(sessionId) {
|
|
71
|
+
return fetch('/dsh-delete-session/delete', {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
headers: { 'content-type': 'application/json' },
|
|
74
|
+
body: JSON.stringify({ sessionId }),
|
|
75
|
+
}).then(async (res) => {
|
|
76
|
+
let data = {}
|
|
77
|
+
try { data = await res.json() } catch { /* keep {} */ }
|
|
78
|
+
if (!res.ok || !data.ok) {
|
|
79
|
+
const code = data && data.code
|
|
80
|
+
const message = code === 'busy'
|
|
81
|
+
? t('busy')
|
|
82
|
+
: code === 'not-found'
|
|
83
|
+
? t('notFound')
|
|
84
|
+
: (data && data.error) || `HTTP ${res.status}`
|
|
85
|
+
throw new Error(message)
|
|
86
|
+
}
|
|
87
|
+
return data
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function deleteNow(info) {
|
|
92
|
+
postDelete(info.id)
|
|
93
|
+
.then(() => {
|
|
94
|
+
toast(t('done'))
|
|
95
|
+
refreshList()
|
|
96
|
+
})
|
|
97
|
+
.catch((reason) => toast(t('failed') + String((reason && reason.message) || reason), true))
|
|
98
|
+
}
|
|
99
|
+
|
|
55
100
|
function browserLang() {
|
|
56
101
|
if (typeof navigator === 'undefined') return 'zh'
|
|
57
102
|
for (const tag of (navigator.languages || []).concat([navigator.language])) {
|
|
@@ -118,7 +163,7 @@ window.__ModuleLoader__.load({
|
|
|
118
163
|
function ensureStyle() {
|
|
119
164
|
if (document.querySelector('style[data-dsh-delete-session]')) return
|
|
120
165
|
const style = document.createElement('style')
|
|
121
|
-
style.dataset.
|
|
166
|
+
style.dataset.dshDeleteSession = '1'
|
|
122
167
|
style.textContent = CSS
|
|
123
168
|
document.head.appendChild(style)
|
|
124
169
|
}
|
|
@@ -188,6 +233,15 @@ window.__ModuleLoader__.load({
|
|
|
188
233
|
ack.appendChild(checkbox)
|
|
189
234
|
ack.appendChild(ackText)
|
|
190
235
|
|
|
236
|
+
const skip = document.createElement('label')
|
|
237
|
+
skip.className = 'dsdel-ack'
|
|
238
|
+
const skipBox = document.createElement('input')
|
|
239
|
+
skipBox.type = 'checkbox'
|
|
240
|
+
const skipText = document.createElement('span')
|
|
241
|
+
skipText.textContent = t('dontAsk')
|
|
242
|
+
skip.appendChild(skipBox)
|
|
243
|
+
skip.appendChild(skipText)
|
|
244
|
+
|
|
191
245
|
const error = document.createElement('p')
|
|
192
246
|
error.className = 'dsdel-error'
|
|
193
247
|
error.style.display = 'none'
|
|
@@ -210,6 +264,7 @@ window.__ModuleLoader__.load({
|
|
|
210
264
|
dialog.appendChild(meta)
|
|
211
265
|
dialog.appendChild(text)
|
|
212
266
|
dialog.appendChild(ack)
|
|
267
|
+
dialog.appendChild(skip)
|
|
213
268
|
dialog.appendChild(error)
|
|
214
269
|
dialog.appendChild(actions)
|
|
215
270
|
backdrop.appendChild(dialog)
|
|
@@ -232,23 +287,9 @@ window.__ModuleLoader__.load({
|
|
|
232
287
|
cancel.disabled = true
|
|
233
288
|
confirm.textContent = t('deleting')
|
|
234
289
|
error.style.display = 'none'
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
body: JSON.stringify({ sessionId: info.id }),
|
|
239
|
-
})
|
|
240
|
-
.then(async (res) => {
|
|
241
|
-
let data = {}
|
|
242
|
-
try { data = await res.json() } catch { /* keep {} */ }
|
|
243
|
-
if (!res.ok || !data.ok) {
|
|
244
|
-
const code = data && data.code
|
|
245
|
-
const message = code === 'busy'
|
|
246
|
-
? t('busy')
|
|
247
|
-
: code === 'not-found'
|
|
248
|
-
? t('notFound')
|
|
249
|
-
: (data && data.error) || `HTTP ${res.status}`
|
|
250
|
-
throw new Error(message)
|
|
251
|
-
}
|
|
290
|
+
if (skipBox.checked) setSkipConfirm()
|
|
291
|
+
postDelete(info.id)
|
|
292
|
+
.then(() => {
|
|
252
293
|
backdrop.remove()
|
|
253
294
|
toast(t('done'))
|
|
254
295
|
refreshList()
|
|
@@ -298,7 +339,8 @@ window.__ModuleLoader__.load({
|
|
|
298
339
|
e.stopPropagation()
|
|
299
340
|
e.preventDefault()
|
|
300
341
|
closeMenu()
|
|
301
|
-
|
|
342
|
+
if (skipConfirm() && !e.shiftKey) deleteNow(info)
|
|
343
|
+
else openDialog(info)
|
|
302
344
|
})
|
|
303
345
|
wrap.appendChild(button)
|
|
304
346
|
viewport.appendChild(wrap)
|