dsh-session-conductor 1.3.8 → 1.3.9
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 +7 -1
- package/lib/apply.js +18 -0
- package/lib/client-parts/components/panel.js +177 -0
- package/lib/client.js +177 -0
- package/lib/core/config.js +3 -0
- package/lib/core/index-store.js +148 -0
- package/lib/features/session-messaging/tools.js +7 -1
- package/lib/features/session-ops-routes.js +132 -1
- package/lib/features/session-ops.js +90 -40
- package/lib/features/trash.js +206 -0
- package/lib/features/value-index.js +11 -26
- package/lib/i18n/en.json +24 -9
- package/lib/i18n/zh.json +22 -7
- package/lib/sessions/list-cache.js +11 -29
- package/lib/sessions/list.js +11 -0
- package/package.json +2 -2
package/lib/i18n/zh.json
CHANGED
|
@@ -13,6 +13,21 @@
|
|
|
13
13
|
"tab.archived": "已归档",
|
|
14
14
|
"tab.active": "活跃",
|
|
15
15
|
"tab.help": "说明",
|
|
16
|
+
"tab.trash": "回收站",
|
|
17
|
+
"trash.retention.label": "保留",
|
|
18
|
+
"trash.retention.unit": "天",
|
|
19
|
+
"trash.retention.save": "保存",
|
|
20
|
+
"trash.undo": "撤销上次删除",
|
|
21
|
+
"trash.undo.title": "还原最近一批({n} 个)",
|
|
22
|
+
"trash.restoreSelected": "还原选中 ({n})",
|
|
23
|
+
"trash.selectAll": "全选",
|
|
24
|
+
"trash.empty": "一键清空",
|
|
25
|
+
"trash.emptyConfirm": "清空回收站会立即真删 {n} 个会话(不可恢复),确定吗?",
|
|
26
|
+
"trash.restore": "还原",
|
|
27
|
+
"trash.emptyList": "回收站是空的",
|
|
28
|
+
"trash.hint": "删除只是打标记、文件还在;到期(保留天数)或一键清空才真正删盘",
|
|
29
|
+
"trash.remaining": "剩 {n} 天",
|
|
30
|
+
"trash.nothingToUndo": "没有可撤销的删除",
|
|
16
31
|
"list.empty": "还没有会话",
|
|
17
32
|
"list.archivedEmpty": "没有已归档的会话",
|
|
18
33
|
"list.activeEmpty": "当前没有活跃会话(live/running)",
|
|
@@ -55,8 +70,8 @@
|
|
|
55
70
|
"action.analyze": "分析",
|
|
56
71
|
"action.busy": "处理中…",
|
|
57
72
|
"action.retry": "重试",
|
|
58
|
-
"confirm.delete.title": "
|
|
59
|
-
"confirm.delete.body": "
|
|
73
|
+
"confirm.delete.title": "确定要删除会话「{title}」吗?",
|
|
74
|
+
"confirm.delete.body": "会话会移入回收站,可在「回收站」页随时还原;只有到期(保留天数,默认 7 天)或一键清空才真正删盘。",
|
|
60
75
|
"action.undo": "撤回消息",
|
|
61
76
|
"undo.preview.empty": "(无文本消息)",
|
|
62
77
|
"confirm.undo.title": "撤回最后一条消息?",
|
|
@@ -72,7 +87,7 @@
|
|
|
72
87
|
"meta.time.months": "{n}个月前",
|
|
73
88
|
"meta.time.years": "{n}年前",
|
|
74
89
|
"help.delete.title": "删除会话(本插件新增)",
|
|
75
|
-
"help.delete.desc": "
|
|
90
|
+
"help.delete.desc": "内置界面没有任何删除会话的入口,本插件补上了。删除**只打标记、不动会话文件**:会话会进「回收站」标签页,可单条还原、多选还原,或按批次撤销最近一次删除;运行中的会话拒绝删除。真正删盘只发生在回收站到期(保留天数可设,默认 7 天)或「一键清空」。",
|
|
76
91
|
"help.autoRename.title": "自动重命名(本插件新增)",
|
|
77
92
|
"help.autoRename.desc": "给会话勾选「自动重命名」后,每个回合结束,插件会用 AI 分析最近会话内容;发现主题/方向已明显偏离当前标题时,自动生成新标题并改掉。标题会带上实时状态后缀:「(运行中)」= 正在执行回合、「(已中断)」= 崩溃/错误中断待续跑;回合结束自动更新。分析带 5 分钟最小间隔和新增消息数门槛,避免频繁调用浪费额度。",
|
|
78
93
|
"help.autoContinue.title": "自动续跑(本插件新增)",
|
|
@@ -99,9 +114,9 @@
|
|
|
99
114
|
"search.hits": "命中 {n} 个会话",
|
|
100
115
|
"search.close": "收起结果",
|
|
101
116
|
"deleteBatch.action": "删除选中 ({n})",
|
|
102
|
-
"deleteBatch.confirm.title": "
|
|
103
|
-
"deleteBatch.confirm.body": "
|
|
104
|
-
"deleteBatch.done": "
|
|
117
|
+
"deleteBatch.confirm.title": "确定要删除选中的 {n} 个会话吗?",
|
|
118
|
+
"deleteBatch.confirm.body": "会移入回收站,可随时还原;运行中的会话会被自动跳过。",
|
|
119
|
+
"deleteBatch.done": "已移入回收站 {deleted} 个{skippedText}",
|
|
105
120
|
"deleteBatch.skipped": ",跳过 {n} 个(运行中/不可删)",
|
|
106
121
|
"deleteByRule.action": "筛选",
|
|
107
122
|
"deleteByRule.label.archivedOnly": "仅已归档会话",
|
|
@@ -202,4 +217,4 @@
|
|
|
202
217
|
"armCurNone": "当前:未选择",
|
|
203
218
|
"renderFail": "设置页渲染失败:"
|
|
204
219
|
}
|
|
205
|
-
}
|
|
220
|
+
}
|
|
@@ -7,45 +7,32 @@
|
|
|
7
7
|
// ③ 列表 TTL 缓存与失效(写操作后 invalidateSessionListCache 立即失效)。
|
|
8
8
|
// 列表的构建流程(buildSessionList)在 list.js。
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
import path from "node:path";
|
|
10
|
+
import { getSection, setSection, saveStoreNow } from "../core/index-store.js";
|
|
12
11
|
import { log } from "../shared/log.js";
|
|
13
|
-
import { cfg,
|
|
12
|
+
import { cfg, autoRenameEnabled, effectiveAutoContinue } from "../core/config.js";
|
|
14
13
|
import { continueJobs } from "../core/state.js";
|
|
15
14
|
import { stripArchiveWsPrefix } from "../features/rename/title.js";
|
|
16
15
|
|
|
17
16
|
/** 缓存文件版本(不符视为空缓存)。 */
|
|
18
17
|
const LIST_CACHE_VERSION = 1;
|
|
19
|
-
/** 缓存文件所在子目录。 */
|
|
20
|
-
const LIST_CACHE_SUBDIR = ["storages", "dsh-session-conductor"];
|
|
21
18
|
|
|
22
|
-
/**
|
|
19
|
+
/** 内存缓存:{ version, entries: { [id]: { rev, title, updatedAt, interruption, inspectError, cwd, createdAt, parentSession } } }
|
|
20
|
+
* 落盘统一走 <DSH_HOME>/storages/dsh-session-conductor/index.json 的 list section。 */
|
|
23
21
|
let listDiskCache = null;
|
|
24
|
-
let listDiskCachePath = null;
|
|
25
22
|
let listDiskCacheDirty = false;
|
|
26
23
|
let listDiskCacheTimer = null;
|
|
27
24
|
|
|
28
|
-
/**
|
|
29
|
-
export function listCacheFilePath(ctx) {
|
|
30
|
-
if (listDiskCachePath !== null) return listDiskCachePath;
|
|
31
|
-
const home = resolveDshHome(ctx, cfg);
|
|
32
|
-
listDiskCachePath = home ? path.join(home, ...LIST_CACHE_SUBDIR, "list-cache.json") : "";
|
|
33
|
-
return listDiskCachePath;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** 读落盘缓存(进程内只读一次)。任何异常都退化成空缓存,不向上抛。 */
|
|
25
|
+
/** 读缓存(进程内只读一次)。任何异常都退化成空缓存,不向上抛。 */
|
|
37
26
|
export function loadListDiskCache(ctx) {
|
|
38
27
|
if (listDiskCache !== null) return listDiskCache;
|
|
39
28
|
listDiskCache = { version: LIST_CACHE_VERSION, entries: {} };
|
|
40
|
-
const file = listCacheFilePath(ctx);
|
|
41
|
-
if (!file) return listDiskCache;
|
|
42
29
|
try {
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
listDiskCache = { version: LIST_CACHE_VERSION, entries:
|
|
30
|
+
const section = getSection(ctx, "list");
|
|
31
|
+
if (section?.entries && typeof section.entries === "object") {
|
|
32
|
+
listDiskCache = { version: LIST_CACHE_VERSION, entries: section.entries };
|
|
46
33
|
}
|
|
47
34
|
} catch {
|
|
48
|
-
//
|
|
35
|
+
// 索引不可用:按空缓存继续,本次解析完会覆盖写入
|
|
49
36
|
}
|
|
50
37
|
return listDiskCache;
|
|
51
38
|
}
|
|
@@ -67,14 +54,10 @@ export function scheduleSaveListDiskCache(ctx) {
|
|
|
67
54
|
/** 立即原子落盘(写临时文件再 rename,避免下次启动读到半个文件)。 */
|
|
68
55
|
export function saveListDiskCacheNow(ctx) {
|
|
69
56
|
if (!listDiskCacheDirty || listDiskCache === null) return;
|
|
70
|
-
const file = listCacheFilePath(ctx);
|
|
71
|
-
if (!file) return;
|
|
72
57
|
listDiskCacheDirty = false;
|
|
73
58
|
try {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
writeFileSync(tmpPath, JSON.stringify(listDiskCache), "utf8");
|
|
77
|
-
renameSync(tmpPath, file);
|
|
59
|
+
setSection(ctx, "list", { entries: listDiskCache.entries });
|
|
60
|
+
saveStoreNow(ctx);
|
|
78
61
|
} catch (error) {
|
|
79
62
|
// 落盘失败只是让下次重新解析,不影响列表功能;记录下来便于诊断
|
|
80
63
|
log(ctx, `会话列表缓存落盘失败(不影响功能): ${String(error?.message ?? error)}`);
|
|
@@ -195,7 +178,6 @@ export function settleListBuild(promise, items) {
|
|
|
195
178
|
/** 测试钩子:清空列表缓存状态(单测在场景之间调用)。 */
|
|
196
179
|
export function resetListCacheForTest() {
|
|
197
180
|
listDiskCache = null;
|
|
198
|
-
listDiskCachePath = null;
|
|
199
181
|
listDiskCacheDirty = false;
|
|
200
182
|
if (listDiskCacheTimer !== null) clearTimeout(listDiskCacheTimer);
|
|
201
183
|
listDiskCacheTimer = null;
|
package/lib/sessions/list.js
CHANGED
|
@@ -221,6 +221,17 @@ export async function buildSessionList(ctx, opts = {}) { // dsh-skip-func-length
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
// 回收站里的会话不进列表:删除只是打标记,文件仍在磁盘上,只是对外隐藏。
|
|
225
|
+
try {
|
|
226
|
+
const { trashedIds } = await import("../features/trash.js");
|
|
227
|
+
const hidden = trashedIds(ctx);
|
|
228
|
+
if (hidden.size > 0) {
|
|
229
|
+
for (let i = items.length - 1; i >= 0; i -= 1) {
|
|
230
|
+
if (hidden.has(items[i].id)) items.splice(i, 1);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
} catch { /* 回收站不可用不影响列表 */ }
|
|
234
|
+
|
|
224
235
|
items.sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
|
|
225
236
|
return items;
|
|
226
237
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-session-conductor",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.9",
|
|
4
4
|
"description": "DSH session management enhancement: archive/restore sessions, batch & conditional delete, AI auto-rename, interrupted-session auto-resume, release idle sessions, workspace grouping, undo last message, repair damaged session logs, value analysis, full-text search, per-member model switching (list_models / set_member_model), and plan/closing template injection (system-prompt + context).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -66,4 +66,4 @@
|
|
|
66
66
|
"./skills/dsh-session-official-doc.md"
|
|
67
67
|
]
|
|
68
68
|
}
|
|
69
|
-
}
|
|
69
|
+
}
|