dsh-sessions-manager 3.5.2 → 3.5.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.en.md +2 -2
- package/README.md +2 -2
- package/lib/client.js +9 -2
- package/lib/client.js.map +2 -2
- package/lib/index.js +131 -118
- package/lib/index.js.map +4 -4
- package/package.json +1 -1
- package/src/client/index.jsx +16 -3
- package/src/compat/persistence.js +2 -0
- package/src/index.js +20 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-sessions-manager",
|
|
3
3
|
"description": "DSH 设置面板会话管理器:归档 / 恢复 / 彻底删除 / 移动到其他工作区,带工作区标签与会话日期;统一「会话管理」面板。Session manager for the DeepSeek Harness settings panel — archive / restore / permanently delete / move sessions across workspaces, with workspace tags & session dates in one unified panel.",
|
|
4
|
-
"version": "3.5.
|
|
4
|
+
"version": "3.5.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"exports": {
|
package/src/client/index.jsx
CHANGED
|
@@ -1353,9 +1353,15 @@ function installSidebarSessionMenuAug() {
|
|
|
1353
1353
|
sub.setAttribute('data-dsm-sub', '')
|
|
1354
1354
|
sub.innerHTML = '<div class="dsm-sub-loading">加载工作区…</div>'
|
|
1355
1355
|
const r = moveBtn.getBoundingClientRect()
|
|
1356
|
-
|
|
1357
|
-
|
|
1356
|
+
// Fixed-position card: once the async content renders it can be tall or
|
|
1357
|
+
// wide enough to hang past the viewport edges, so re-clamp both anchors
|
|
1358
|
+
// against the rendered size.
|
|
1359
|
+
const placeSub = () => {
|
|
1360
|
+
sub.style.top = Math.max(8, Math.min(Math.round(r.top - 4), window.innerHeight - sub.offsetHeight - 8)) + 'px'
|
|
1361
|
+
sub.style.left = Math.max(8, Math.min(Math.round(r.right + 10), window.innerWidth - sub.offsetWidth - 8)) + 'px'
|
|
1362
|
+
}
|
|
1358
1363
|
document.body.appendChild(sub)
|
|
1364
|
+
placeSub()
|
|
1359
1365
|
const closeSub = () => {
|
|
1360
1366
|
activeSubClose = null
|
|
1361
1367
|
if (sub.parentNode) sub.remove()
|
|
@@ -1384,7 +1390,7 @@ function installSidebarSessionMenuAug() {
|
|
|
1384
1390
|
const items = ws.items || []
|
|
1385
1391
|
const cur = (sess.items || []).find((x) => x.sessionId === info.id)
|
|
1386
1392
|
const curPath = cur ? cur.workspacePath : (info.cwd || null)
|
|
1387
|
-
if (!items.length) { sub.innerHTML = '<div class="dsm-sub-empty">(暂无可用工作区)</div>'; return }
|
|
1393
|
+
if (!items.length) { sub.innerHTML = '<div class="dsm-sub-empty">(暂无可用工作区)</div>'; placeSub(); return }
|
|
1388
1394
|
sub.innerHTML = ''
|
|
1389
1395
|
items.forEach((w) => {
|
|
1390
1396
|
const isCur = !!curPath && w.path === curPath
|
|
@@ -1414,8 +1420,10 @@ function installSidebarSessionMenuAug() {
|
|
|
1414
1420
|
})
|
|
1415
1421
|
sub.appendChild(b)
|
|
1416
1422
|
})
|
|
1423
|
+
placeSub()
|
|
1417
1424
|
}).catch((e) => {
|
|
1418
1425
|
sub.innerHTML = '<div class="dsm-sub-err">' + escapeHtml(String((e && e.message) || e)) + '</div>'
|
|
1426
|
+
placeSub()
|
|
1419
1427
|
})
|
|
1420
1428
|
}
|
|
1421
1429
|
const openDeleteConfirm = (id) => {
|
|
@@ -1510,6 +1518,11 @@ function installSidebarSessionMenuAug() {
|
|
|
1510
1518
|
viewport.appendChild(del.wrap)
|
|
1511
1519
|
// 标记未读 goes to the very top of the menu (above DSH's native items).
|
|
1512
1520
|
viewport.insertBefore(mark.wrap, viewport.firstElementChild)
|
|
1521
|
+
// DSH's portalled Menu clamped its position using the height it measured
|
|
1522
|
+
// before this shim injected rows, so the grown card can hang past the
|
|
1523
|
+
// viewport bottom and cover the sidebar foot. Reuse the host's own
|
|
1524
|
+
// placement by firing the resize event it listens for while open.
|
|
1525
|
+
window.dispatchEvent(new Event('resize'))
|
|
1513
1526
|
}
|
|
1514
1527
|
|
|
1515
1528
|
const seen = new WeakSet()
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
// is an opaque change token valid ONLY within one service instance and one
|
|
14
14
|
// session id (see src/session-meta-cache.js).
|
|
15
15
|
|
|
16
|
+
import { locateSessionArtifacts } from '../handle-era-paths.js'
|
|
17
|
+
|
|
16
18
|
const DEFAULT_CHUNK = 400
|
|
17
19
|
// 防御上限:一次 inspect 的分块循环绝不能无限自旋(后端 read 行为异常时快速失败)。
|
|
18
20
|
const MAX_CHUNKS = 20000
|
package/src/index.js
CHANGED
|
@@ -625,12 +625,31 @@ export function apply(ctx) {
|
|
|
625
625
|
const entry = store.items.find((t) => String(t.sessionId) === sid)
|
|
626
626
|
if (!entry) { const error = new Error('回收站中找不到该会话'); error.status = 404; throw error }
|
|
627
627
|
let target = null
|
|
628
|
+
let locatedHeader = null
|
|
628
629
|
try {
|
|
629
630
|
const entries = await persistence.listEntries()
|
|
630
631
|
const current = entries.find((entry) => entry.id === sid)
|
|
631
|
-
|
|
632
|
+
locatedHeader = current ? current.header : null
|
|
633
|
+
// locateVerified:legacy 走官方 locate;handle 时代官方收走了 locate,
|
|
634
|
+
// 改由三层守卫推导(root → 目录结构 → id 归属),失败返回 null。
|
|
635
|
+
// 比仅靠回收站条目里的 originalPath 更可靠:originalPath 过期或缺失时
|
|
636
|
+
// 仍能从当前存储布局重新推导。
|
|
637
|
+
const located = current ? await persistence.locateVerified(current.header) : null
|
|
632
638
|
if (located && typeof located.path === 'string') target = located.path
|
|
633
639
|
} catch (e) {}
|
|
640
|
+
// 幽灵记录兜底:会话不在 list 里(后端索引滞后/索引缺失)但日志仍在盘上。
|
|
641
|
+
// 用 statSession 拿官方 header,再走守卫推导,避免退化成「只删单文件」
|
|
642
|
+
// 或直接 409 拒绝。
|
|
643
|
+
if (!locatedHeader && typeof persistence.statSession === 'function') {
|
|
644
|
+
try {
|
|
645
|
+
const snap = await persistence.statSession(sid)
|
|
646
|
+
if (snap && snap.header) {
|
|
647
|
+
locatedHeader = snap.header
|
|
648
|
+
const located = await persistence.locateVerified(snap.header)
|
|
649
|
+
if (located && typeof located.path === 'string') target = located.path
|
|
650
|
+
}
|
|
651
|
+
} catch (e) {}
|
|
652
|
+
}
|
|
634
653
|
if (!target && typeof entry.originalPath === 'string') target = entry.originalPath
|
|
635
654
|
if (!target) {
|
|
636
655
|
const error = new Error('无法确认该会话的物理日志位置,已停止永久删除')
|