@michengai/dsh-archive-manager 1.1.10 → 1.1.11
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 +13 -0
- package/CHANGELOG.zh-CN.md +13 -0
- package/README.md +9 -16
- package/README.ru.md +9 -16
- package/README.zh-CN.md +9 -16
- package/lib/archive-discovery.js +5 -89
- package/lib/client.js +5 -23
- package/lib/host-install.js +3 -18
- package/lib/projcache.js +3 -331
- package/lib/workspace.js +223 -375
- package/package.json +1 -1
- package/lib/session-repair.js +0 -211
- package/lib/tombstone.js +0 -18
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
Published release notes are retained below; new versions are added without removing earlier entries.
|
|
6
6
|
|
|
7
|
+
## 1.1.11 - 2026-10-24
|
|
8
|
+
|
|
9
|
+
- Remove session turn counting and turn-based sorting: purged background batch uncompressed event reading logic for counting dialogue turns (sessionDetails / turnCount / countConversationTurns), removed turn indicators from session metadata rows, and removed "Most/Fewest turns" sort options, significantly reducing CPU and disk IO overhead during list navigation.
|
|
10
|
+
- Remove obsolete session log mutation and repair logic: purged the defunct diagnoseSession and repairSession methods along with the session-repair module, removing the log error warning banner from the UI. Orphan subagent cleanup is now directly integrated into the Organizer panel for clean one-click reclamation.
|
|
11
|
+
- Support detecting and cleaning up orphan subagents left behind by external deletions (#72): verify physical artifact absence to confirm parent deletion, accurately recognize both regular and context-seeded subagents (excluding user fork branches), and enforce safety gates in cleanup to prevent deleting live subagents.
|
|
12
|
+
- Support sorting by recently archived order (#75): added a "Recently archived" option to the sort menu in the archived sessions view, ordering sessions and projects based on the host's archive queue order so newly archived chats can be quickly found and restored.
|
|
13
|
+
- Remove all historical projection-cache scanning, identity checks, and handoff logic (#76), so activation no longer waits for per-record session-log reads. Cache rebuilding is host-owned and on demand; permanent deletion directly removes the cache row without suppressing later official writes.
|
|
14
|
+
- Align date range filter text color: removed the faded placeholder styling when no date is selected, matching the primary text color used by adjacent view and project dropdown buttons.
|
|
15
|
+
- Remove automatic full-log reads and official projection-cache write-backs when opening the archive list, along with the follow-up list refresh. Archive metadata only returns header creation times; preview and search remain available.
|
|
16
|
+
- Remove the historical file-upload resolver conflict shim: the current entry overlays the official workspace instance without replacing the service or restarting `sessionController`; the plugin no longer mutates the global `fileUploads` registrar.
|
|
17
|
+
- Remove all write-barrier and workspace deletion tombstones for permanent deletion. Deletion directly removes transcript directories, cleans the official cache row, and clears in-memory indexing; subsequent cache writes and host indexing follow native behavior.
|
|
18
|
+
- Upgrade boundary: historical plugin cache files are no longer read or automatically deleted. Cold sessions without official cache entries may initially lack list titles; log reads recover titles, and restoring a live session lets the host persist its cache. No extra activation is required to import old caches.
|
|
19
|
+
|
|
7
20
|
## 1.1.10 - 2026-10-24
|
|
8
21
|
|
|
9
22
|
- Support DeepSeek Harness `0.2.1-rc.3` while retaining all existing supported versions.
|
package/CHANGELOG.zh-CN.md
CHANGED
|
@@ -4,6 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
以下发布说明会持续保留;新增版本时不再删除较早记录。
|
|
6
6
|
|
|
7
|
+
## 1.1.11 - 2026-10-24
|
|
8
|
+
|
|
9
|
+
- 移除会话轮次统计与轮次排序:彻底删除后台分批解压读取事件流以统计会话对话轮次的逻辑(sessionDetails / turnCount / countConversationTurns),移除列表元信息中的轮次文本以及排序菜单中的「轮次最多/最少」选项,显著降低列表加载与翻页时的 CPU 及磁盘 IO 开销。
|
|
10
|
+
- 移除失效的会话日志改写与修复逻辑:彻底清理已无法触发且越界接管的 diagnoseSession / repairSession 方法与 session-repair 模块,移除界面顶部的日志报错警告横幅;无主孤儿子代理清理直接收归至「会话整理」面板中,检测到残留时一键物理清理。
|
|
11
|
+
- 支持扫描并清理外部删除导致的无主孤儿子代理(#72):改用物理工件存在性确证母会话是否已被删除,精准识别普通与播种型子代理(排除用户 fork),一键物理清理释放磁盘空间;清理接口具备安全门禁,防止误伤母会话尚存的正常子代理。
|
|
12
|
+
- 支持按最近归档时间(顺序)排序(#75):在已归档视图的排序菜单中新增「最近归档」选项,基于官方归档队列顺序将最新归档的会话及所属项目置顶展示,方便刚刚归档会话后快速定位与恢复。
|
|
13
|
+
- 移除历史投影缓存的全部扫描、身份核验和交接逻辑(#76),启用插件不再等待逐条读取旧缓存对应的会话日志。缓存完全由官方按需重建;永久删除仅直接清理缓存表,不拦截后续官方写入。
|
|
14
|
+
- 统一时间范围筛选按钮文字颜色与视觉层次:移除未选时间时的弱色占位符样式,使其与相邻的全部聊天和所有项目下拉按钮保持一致的亮色正文质感。
|
|
15
|
+
- 移除打开归档列表时自动读取完整日志并补写官方投影缓存的逻辑,以及补缓存后的列表刷新联动。归档元数据只返回头部创建时间,保留预览与搜索。
|
|
16
|
+
- 移除历史文件上传解析器冲突 shim:当前入口只在官方工作区实例上叠加方法,不再替换服务或触发 sessionController 重启;插件不再改写全局 fileUploads 注册器。
|
|
17
|
+
- 移除物理删除的写屏障与工作区删除墓碑:删除仅执行物理转录目录删除、官方投影缓存单行清理及当前内存索引遗忘,后续写入及索引行为完全交还宿主原生逻辑。
|
|
18
|
+
- 升级边界:旧插件缓存文件不再读取或自动删除;官方缓存缺失的冷会话可能暂缺列表标题,读取日志可恢复标题,恢复为活动会话后由官方持久化缓存。无需为导入旧缓存额外启用插件。
|
|
19
|
+
|
|
7
20
|
## 1.1.10 - 2026-10-24
|
|
8
21
|
|
|
9
22
|
- 支持 DeepSeek Harness `0.2.1-rc.3`,继续兼容此前已支持的宿主版本。
|
package/README.md
CHANGED
|
@@ -33,12 +33,12 @@ Put inactive conversations away and find them again when needed, keeping everyda
|
|
|
33
33
|
- **Automated idle session cleanup**: Specify an idle threshold in days to discover inactive chats, automatically protecting running tasks, interactive prompts, and starred items, with instant undo support.
|
|
34
34
|
- **Native workspace menu integration**: Securely injects an **Archive session** action into the sidebar workspace `...` menu, anchoring an in-place frosted glass confirmation modal following the "what you see is what you archive" principle.
|
|
35
35
|
- **Permanent deletion**: Thoroughly purge unwanted transcripts, cache rows, and indexes with per-item retry reporting.
|
|
36
|
-
- **
|
|
36
|
+
- **Orphan subagent detection & cleanup**: Automatically detect residue subagents whose parent sessions were externally deleted, displaying disk usage and enabling safe one-click reclamation.
|
|
37
37
|
- **Controlled online updates & reverse proxy ready**: Features a toggleable online update switch, enterprise host-level configuration locking, and native baseURI dynamic endpoint resolution for prefix-stripping reverse proxies.
|
|
38
38
|
|
|
39
|
-
##
|
|
39
|
+
## Orphan subagent cleanup
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
When parent sessions are deleted externally or via the host, orphaned subagents may remain on disk. The Archive Manager detects these orphan sessions in the Organizer panel, calculates disk space usage, and provides one-click physical deletion.
|
|
42
42
|
|
|
43
43
|
## Search and preview
|
|
44
44
|
|
|
@@ -49,13 +49,6 @@ The archive page collects read failures, including archived IDs with missing sum
|
|
|
49
49
|
- Search accepts up to 200 query characters and reads batches of at most 20 sessions, sequentially within each batch. Tools, attachments, reasoning, system messages, and plugin injections are excluded. Read failures remain visible and can be retried. Stored text is not the model's current context.
|
|
50
50
|
- There is no persistent full-text index. Large or long conversations can be slow; narrow project, dates, or favorites first. No session-count or latency guarantee has been established. Changing filters prevents later batches and stale results, but cannot interrupt the batch already reading.
|
|
51
51
|
|
|
52
|
-
## Turn counts and location
|
|
53
|
-
|
|
54
|
-
- Both tabs show user submission counts, including image submissions; assistant replies, tool calls, and injected messages do not count as turns.
|
|
55
|
-
- Sort by most or fewest turns; unknown counts remain last. Failed details can be retried.
|
|
56
|
-
- **More** provides separate ID/path copying. Official JSONL storage returns the session directory; other backends use a valid host-provided path. Clipboard operations require browser permission and HTTPS or localhost; failures are reported.
|
|
57
|
-
- Details are read in batches of up to 20 without activating or restoring sessions. Counts include inherited user messages, have no persistent index, and may take time for long logs.
|
|
58
|
-
|
|
59
52
|
## Screenshots
|
|
60
53
|
|
|
61
54
|
Search, favorite, preview, restore, and clean up in **Settings → Archived sessions → Archived**:
|
|
@@ -132,13 +125,13 @@ Two native switches are available:
|
|
|
132
125
|
| **Search & filter** | Open **Settings → Archived sessions** or click **Archive** in the sidebar; search bar automatically covers titles and body messages; use the Codex-style view menu to filter (all / favorites only) and sort; select projects from dropdown; pick dates with the single-field capsule |
|
|
133
126
|
| **Custom calendar & keyboard nav** | Click the date capsule to open the lightweight calendar popover; supports all time and quick presets; provides complete WAI-ARIA keyboard navigation (arrows, Home/End, PageUp/Down, Enter/Space) and real-time range stretch preview |
|
|
134
127
|
| **Quick preview** | Click a match snippet or **More → Quick preview** to inspect context with highlights without restoring |
|
|
135
|
-
| **Adjust ordering** | Sort by update time, creation time,
|
|
128
|
+
| **Adjust ordering** | Sort by recently archived, update time, creation time, or title in the view menu |
|
|
136
129
|
| **Restore a chat** | Click the restore icon on any row; use **More → Restore and open** to resume the chat directly |
|
|
137
130
|
| **Archive entire group** | On **Unarchived**, click the **…** menu next to a group and confirm archiving all chats in that project |
|
|
138
131
|
| **Favorite chats** | Click the star icon on any row; use the view menu to filter starred chats |
|
|
139
132
|
| **Clean up idle chats** | On **Unarchived**, set an idle day threshold, automatically protecting running and starred chats, preview candidates, and confirm |
|
|
140
|
-
| **
|
|
141
|
-
| **
|
|
133
|
+
| **Copy session ID** | Select **Copy session ID** from the **More** menu |
|
|
134
|
+
| **Clean up orphan subagents** | Detect and physically delete orphan subagents in the Organizer panel |
|
|
142
135
|
| **Archive across projects** | Switch to **Unarchived**, select sessions across projects, then click **Archive** and confirm |
|
|
143
136
|
| **Restore or delete in bulk** | Select chats and use the bulk actions, or use the project menu; there are no separate Restore all / Delete all buttons |
|
|
144
137
|
|
|
@@ -190,11 +183,11 @@ dsh --profile web --dump-config
|
|
|
190
183
|
|
|
191
184
|
The configuration should include `ui-workspace-archive-manager` and must not disable official `workspace` or `session-projection-cache`. A leftover `archive-manager-host` override can be removed. On current DSH hosts the official `ui-settings-unarchive-sessions` entry is gone, so this plugin no longer disables it (doing so only warned that the patch entry was missing). If your profile's `cordis.patch.yml` still disables `workspace`, `session-projection-cache`, or `ui-workspace`, remove those overrides and restart.
|
|
192
185
|
|
|
193
|
-
###
|
|
186
|
+
### What happens to historical plugin caches after upgrading?
|
|
194
187
|
|
|
195
|
-
The
|
|
188
|
+
The plugin neither replaces the official projection-cache table nor scans, validates, or migrates historical plugin caches. Opening the archive list does not read complete logs or write back official projections to fill missing cache entries. Session logs remain host-owned, and the host rebuilds derived projections such as titles on demand. Enabling or disabling the plugin does not switch cache tables; there is no need to enable it once just to import old caches.
|
|
196
189
|
|
|
197
|
-
|
|
190
|
+
**A cold session without an official cache entry may initially have no title in the list; refreshing the list alone does not guarantee a rebuild.** Reading the log can recover the title, and restoring the session as live lets the native write path persist its cache. Historical plugin cache files are left untouched: they are neither read nor deleted automatically. See the [changelog](CHANGELOG.md) for details.
|
|
198
191
|
|
|
199
192
|
### How is archiving different from deletion?
|
|
200
193
|
|
package/README.ru.md
CHANGED
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
- **Восстанавливать задачи**: восстановить один чат, выбранные чаты или группу проекта; выбрать все отфильтрованные результаты для массовых действий.
|
|
29
29
|
- **Очищать записи**: безвозвратно удалять ненужные архивы после подтверждения, отслеживать прогресс пакетной обработки и повторять оставшиеся элементы.
|
|
30
30
|
- **Упорядочивать важные чаты**: сохранять избранное и предпросматривать очистку неактивных, защищая избранное и активную работу.
|
|
31
|
-
-
|
|
31
|
+
- **Очистка сессий-сирот**: автоматически находить и физически удалять остаточные подагенты, чьи родительские сессии были удалены.
|
|
32
32
|
|
|
33
33
|
> В этом README описан выпуск 1.0.0. Полный список возможностей и границы обновления — в [истории изменений](CHANGELOG.md).
|
|
34
34
|
|
|
35
|
-
##
|
|
35
|
+
## Очистка подагентов-сирот
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
Когда родительская сессия удалена извне, её дочерние подагенты могут оставаться на диске. Менеджер архива находит такие сессии в панели организации и позволяет физически удалить их в один клик.
|
|
38
38
|
|
|
39
39
|
## Поиск и предпросмотр
|
|
40
40
|
|
|
@@ -45,13 +45,6 @@
|
|
|
45
45
|
- Поиск принимает до 200 символов запроса и читает пакетами максимум по 20 сессий последовательно внутри каждого пакета. Инструменты, вложения, рассуждения, системные сообщения и плагинные вставки исключаются. Ошибки чтения остаются видимыми и их можно повторить. Сохранённый текст — это не текущий контекст модели.
|
|
46
46
|
- Постоянного полнотекстового индекса нет. Большие или длинные беседы могут обрабатываться медленно; сначала сузьте по проекту, датам или избранному. Никаких гарантий по числу сессий или задержке не установлено. Смена фильтров останавливает последующие пакеты и устаревшие результаты, но не может прервать уже читаемый пакет.
|
|
47
47
|
|
|
48
|
-
## Число ходов и местоположение
|
|
49
|
-
|
|
50
|
-
- Обе вкладки показывают число отправок от пользователя, включая отправки изображений; ответы ассистента, вызовы инструментов и вставленные сообщения не считаются ходами.
|
|
51
|
-
- Сортируйте по наибольшему или наименьшему числу ходов; неизвестное число остаётся в конце. Ошибки деталей можно повторить.
|
|
52
|
-
- **Дополнительно** даёт раздельное копирование ID/пути. Официальное хранилище JSONL возвращает каталог сессии; другие бэкенды используют корректный путь, предоставленный хостом. Операции с буфером обмена требуют разрешения браузера и HTTPS или localhost; сбои сообщаются.
|
|
53
|
-
- Детали читаются пакетами до 20, без активации или восстановления сессий. Счётчики включают унаследованные сообщения пользователя, не имеют постоянного индекса и могут занимать время для длинных журналов.
|
|
54
|
-
|
|
55
48
|
## Скриншоты
|
|
56
49
|
|
|
57
50
|
Поиск, избранное, предпросмотр, восстановление и очистка — в **Настройки → Архив сессий → Архив**:
|
|
@@ -102,14 +95,14 @@ dsh plugin --profile web add @michengai/dsh-archive-manager@latest --registry=ht
|
|
|
102
95
|
| Архивировать один чат | Откройте меню сессии на боковой панели и выберите **Заархивировать сессию** |
|
|
103
96
|
| Архивировать рабочую область | Откройте меню рабочей области и выберите **Заархивировать все чаты** |
|
|
104
97
|
| Найти архив | Откройте **Настройки → Архив сессий**, затем выберите поиск по названию/содержимому или фильтруйте по проекту, избранному и датам |
|
|
105
|
-
| Изменить порядок | Сортируйте по времени обновления, времени
|
|
98
|
+
| Изменить порядок | Сортируйте по недавнему архивированию, времени обновления, времени создания или названию |
|
|
106
99
|
| Восстановить один чат | Щёлкните значок восстановления или выберите **Дополнительно → Восстановить и открыть** |
|
|
107
100
|
| Архивировать проект или несгруппированные чаты | На вкладке **Незаархивированные** откройте меню **…** группы и подтвердите архивирование всех чатов этой группы независимо от фильтров поиска |
|
|
108
101
|
| Избранное для чата | Щёлкните звезду справа; используйте выпадающий список избранного для фильтрации |
|
|
109
102
|
| Предпросмотр архивированного | Щёлкните фрагмент совпадения или **Дополнительно → Быстрый предпросмотр** |
|
|
110
103
|
| Очистить неактивные чаты | На вкладке **Незаархивированные** задайте **Дни простоя**, просмотрите кандидатов и подтвердите |
|
|
111
|
-
|
|
|
112
|
-
|
|
|
104
|
+
| Скопировать ID | Скопируйте ID сессии через меню **Дополнительно** |
|
|
105
|
+
| Очистить подагентов-сирот | Обнаружить и физически удалить оставшиеся подагенты в панели организации |
|
|
113
106
|
| Архивировать по проектам | Переключитесь на **Незаархивированные**, выберите сессии в разных проектах, затем нажмите **Архивировать** и подтвердите |
|
|
114
107
|
| Массовое восстановление или удаление | Выберите чаты и используйте массовые действия или меню проекта; отдельных кнопок «Восстановить всё» / «Удалить всё» нет |
|
|
115
108
|
|
|
@@ -161,11 +154,11 @@ dsh --profile web --dump-config
|
|
|
161
154
|
|
|
162
155
|
В конфигурации должен присутствовать `ui-workspace-archive-manager`, и он не должен отключать официальные `workspace` или `session-projection-cache`. Оставшийся override `archive-manager-host` можно удалить. В текущих хостах DSH официальной записи `ui-settings-unarchive-sessions` уже нет, поэтому плагин больше её не отключает (иначе dump-config предупреждает, что запись патча не найдена). Если `cordis.patch.yml` вашего профиля всё ещё отключает `workspace`, `session-projection-cache` или `ui-workspace`, удалите эти override и перезапустите.
|
|
163
156
|
|
|
164
|
-
###
|
|
157
|
+
### Что происходит со старым кэшем плагина после обновления?
|
|
165
158
|
|
|
166
|
-
|
|
159
|
+
Плагин не заменяет официальную таблицу кэша проекций и больше не сканирует, не проверяет и не переносит старый кэш. Открытие списка архива не читает полные журналы и не дописывает официальный кэш для восстановления отсутствующих записей. Журналы сессий остаются у хоста, который восстанавливает производные данные, включая названия, по мере необходимости. Включение и отключение плагина не переключает таблицы кэша; включать его специально для импорта больше не нужно.
|
|
167
160
|
|
|
168
|
-
|
|
161
|
+
**У холодной сессии без официального кэша название может временно отсутствовать в списке; одно обновление списка не гарантирует восстановление.** Чтение журнала позволяет восстановить название, а восстановление сессии как активной запускает штатную запись кэша. Старые файлы кэша сохраняются без изменений: плагин не читает и не удаляет их автоматически. Подробности — в [журнале изменений](CHANGELOG.md).
|
|
169
162
|
|
|
170
163
|
### Чем архивирование отличается от удаления?
|
|
171
164
|
|
package/README.zh-CN.md
CHANGED
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
- **智能闲置会话整理**:自定义闲置天数,自动分析并排除正在运行、等待交互及已收藏的关键会话,支持预览候选后确认归档,并提供误操作撤回机制。
|
|
34
34
|
- **原生侧边栏菜单注入**:在原生侧栏工作区 `...` 菜单中安全注入「归档会话」项,弹出锚定工作区行的毛玻璃二次确认框,严格遵循「所见即所归」原则。
|
|
35
35
|
- **永久彻底清理**:确认后永久删除不再需要的会话,彻底清除物理日志、索引与缓存,支持错误项独立重试。
|
|
36
|
-
-
|
|
36
|
+
- **无主孤儿子代理检测与物理清理**:自动探测母会话已被外部物理删除的残留子代理,在会话整理中直观展示空间占用并支持一键物理释放。
|
|
37
37
|
- **可控在线更新与反向代理适配**:提供独立在线更新开关与企业级宿主配置硬锁定;原生适配反代子路径前缀部署。
|
|
38
38
|
|
|
39
|
-
##
|
|
39
|
+
## 孤儿子代理清理
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
当母会话在外部或通过系统被物理删除后,其衍生生成的子代理可能残留于磁盘中。归档管理器在「会话整理」面板中会自动检测是否存在此类无主残留,精准识别并展示占用空间,支持一键安全释放磁盘。
|
|
42
42
|
|
|
43
43
|
## 检索与预览
|
|
44
44
|
|
|
@@ -52,13 +52,6 @@
|
|
|
52
52
|
- 检索逐批读取,每批最多 20 条会话,批内逐条读取;关键词最多 200 字符。预览每条最多 2000 个 UTF-16 码元,截断保留完整 Unicode 字符,较长内容请打开完整会话。
|
|
53
53
|
- 搜索与预览不包含工具输出、附件、推理、系统或插件注入消息;读取失败会显示详情并支持重试。检索的是持久化原始文本,不等同于模型当前上下文。
|
|
54
54
|
- 未建立持久化全文索引,大量或超长会话可能需要较久,建议先缩小项目、日期或收藏范围;尚无可承诺的会话数量上限或响应时延;更改条件会停止后续批次,正在读取的单批仍会完成,但旧结果不会覆盖新筛选。
|
|
55
|
-
## 轮次与定位
|
|
56
|
-
|
|
57
|
-
- 已归档和未归档列表均在时间旁显示轮次。每条用户提交消息算一轮,包括图片消息;助手回复、工具调用和插件注入不计入。
|
|
58
|
-
- 排序菜单新增「轮次最多/轮次最少」,轮次相同按更新时间及标题排序。读取失败显示「轮次未知」,放在已知轮次之后,并提供失败明细和重试。
|
|
59
|
-
- 每行「更多」菜单提供「复制会话 ID/复制会话路径」。官方 JSONL 存储复制会话目录,其他后端复制宿主提供且存在的文件路径;路径缺失会提示,不猜测路径。
|
|
60
|
-
- 详情每批读取最多 20 条,不激活或恢复会话。统计来自原始日志;分支中继承的用户消息也计入。较多长日志可能需要等待,未建立持久化轮次索引。
|
|
61
|
-
- 剪贴板需要 HTTPS 或本机地址及浏览器权限;复制失败会明确提示,不显示成功。
|
|
62
55
|
|
|
63
56
|
## 界面预览
|
|
64
57
|
|
|
@@ -136,15 +129,15 @@ dsh plugin --profile web add @michengai/dsh-archive-manager@latest --registry=ht
|
|
|
136
129
|
| **检索与筛选** | 打开「设置 → 归档会话」或点击侧边栏「归档」,搜索框自动联合检索标题与正文;使用 Codex 风格视图菜单切换「全部会话 / 只看收藏」与排序;按「所有项目」下拉过滤特定项目;使用单字段日期胶囊选择时间范围 |
|
|
137
130
|
| **自研日历与键盘漫游** | 点击日期胶囊展开轻量日历浮层,提供全部时间与常用预设;支持完整键盘无障碍漫游(上下左右键移动、Home/End 周首周末跳转、PageUp/Down 跨月切换、Enter/Space 选定),并提供区间高亮实时拉伸预览 |
|
|
138
131
|
| **快速预览** | 点击命中片段或「更多 → 快速预览」,无需恢复即可查看上下文与原文高亮 |
|
|
139
|
-
| **调整排序** |
|
|
132
|
+
| **调整排序** | 统一在视图菜单中按最近归档、更新时间、创建时间、按字母顺序排序 |
|
|
140
133
|
| **恢复会话** | 点击会话右侧恢复图标;「更多」菜单可「恢复打开」直接进入原会话继续对话 |
|
|
141
134
|
| **项目整体归档** | 在「未归档」页点击分组右侧“…”菜单,确认归档该组全部聊天(不受搜索影响) |
|
|
142
135
|
| **收藏会话** | 点击行右侧星标,使用视图菜单「只看收藏」快速过滤重要会话 |
|
|
143
136
|
| **整理闲置会话** | 在未归档页设置闲置天数,自动排除运行中、等待交互与收藏的会话,预览并确认归档 |
|
|
144
137
|
| **撤回归档** | 批量归档后可在关闭页面前点击「撤回本次归档」,安全恢复误归档会话 |
|
|
145
138
|
| **永久彻底删除** | 勾选单条或多条会话后点击「删除」,二次确认后彻底清除日志与缓存,支持错误项重试 |
|
|
146
|
-
|
|
|
147
|
-
|
|
|
139
|
+
| **清理孤儿子代理** | 在「会话整理」面板中检测外部删除残留的无主子代理并一键物理释放 |
|
|
140
|
+
| **复制会话标识** | 在更多菜单选择「复制会话 ID」快捷复制 |
|
|
148
141
|
|
|
149
142
|
页面默认打开「已归档」,右侧「未归档」用于批量归档。切换 TAB 会清空选择;切换搜索或项目筛选会保留已选会话。批量操作前留意隐藏的已选数量,或先清空选择。
|
|
150
143
|
|
|
@@ -194,11 +187,11 @@ dsh --profile web --dump-config
|
|
|
194
187
|
|
|
195
188
|
配置中应包含 `ui-workspace-archive-manager`,且不应再禁用官方 `workspace` 或 `session-projection-cache`。若还留着 `archive-manager-host` 的禁用覆盖,可以删掉。当前 DSH 宿主已无官方 `ui-settings-unarchive-sessions` 入口,本插件不再对其 disable(否则 dump-config 会告警条目不存在)。若 profile 的 `cordis.patch.yml` 仍禁用 `workspace`、`session-projection-cache` 或 `ui-workspace`,请移除这些覆盖,再重启。
|
|
196
189
|
|
|
197
|
-
###
|
|
190
|
+
### 从旧版升级后,历史缓存如何处理?
|
|
198
191
|
|
|
199
|
-
|
|
192
|
+
插件不再接管官方投影缓存表,也不再扫描、核验或迁移旧插件缓存;打开归档列表不会为了补缓存而读取完整日志或写回官方投影。会话日志仍由宿主保存,标题等投影由官方按需重建;启用或停用插件不会切换缓存表,也不需要为导入旧缓存而额外启用一次。
|
|
200
193
|
|
|
201
|
-
|
|
194
|
+
**官方缓存缺失的冷会话,列表可能暂时不显示已有标题;仅刷新列表不保证重建。** 官方读取日志可恢复标题,恢复为活动会话后由原生写入路径持久化缓存。旧插件缓存文件保留原样,不自动读取或删除。完整变更见[更新日志](CHANGELOG.zh-CN.md)。
|
|
202
195
|
|
|
203
196
|
### 归档和删除有什么区别?
|
|
204
197
|
|
package/lib/archive-discovery.js
CHANGED
|
@@ -46,34 +46,6 @@ const previewResultSchema = { parse(input) {
|
|
|
46
46
|
})
|
|
47
47
|
};
|
|
48
48
|
} };
|
|
49
|
-
const detailsInputSchema = { parse(input) {
|
|
50
|
-
const value = record(input);
|
|
51
|
-
if (!value || !Array.isArray(value.sessionIds) || !value.sessionIds.length || value.sessionIds.length > 20) throw new TypeError("\u6BCF\u6B21\u987B\u5305\u542B 1\uFF5E20 \u4E2A\u4F1A\u8BDD");
|
|
52
|
-
return { sessionIds: [...new Set(value.sessionIds.map(id))] };
|
|
53
|
-
} };
|
|
54
|
-
const detailsResultSchema = { parse(input) {
|
|
55
|
-
const value = record(input);
|
|
56
|
-
if (!value || !Array.isArray(value.items) || value.items.length > 20) throw new TypeError("\u4F1A\u8BDD\u8BE6\u60C5\u65E0\u6548");
|
|
57
|
-
return { items: value.items.map(record).map((row) => ({ sessionId: id(row.sessionId), ...row.createdAt !== void 0 ? { createdAt: sequence(row.createdAt) } : {}, turnCount: row.turnCount === null ? null : sequence(row.turnCount), path: row.path === null ? null : boundedString(row.path, 32768), error: boundedString(row.error, 500) })) };
|
|
58
|
-
} };
|
|
59
|
-
function countConversationTurns(events) {
|
|
60
|
-
if (!Array.isArray(events)) throw new TypeError("\u4F1A\u8BDD\u65E5\u5FD7\u65E0\u6548");
|
|
61
|
-
return events.filter((value) => {
|
|
62
|
-
if (!value || typeof value !== "object" || !("type" in value) || value.type !== "user/message") return false;
|
|
63
|
-
const data = "data" in value ? value.data : void 0;
|
|
64
|
-
const message = (data && typeof data === "object" && "message" in data ? data.message : void 0) ?? data;
|
|
65
|
-
if (!message) return false;
|
|
66
|
-
const source = typeof message === "object" && "source" in message ? message.source : void 0;
|
|
67
|
-
const kind = source && typeof source === "object" && "kind" in source ? source.kind : void 0;
|
|
68
|
-
return !kind || kind === "user";
|
|
69
|
-
}).length;
|
|
70
|
-
}
|
|
71
|
-
function compareTurnCounts(left, right, order) {
|
|
72
|
-
const a = typeof left === "number" && Number.isSafeInteger(left) && left >= 0;
|
|
73
|
-
const b = typeof right === "number" && Number.isSafeInteger(right) && right >= 0;
|
|
74
|
-
if (a !== b) return a ? -1 : 1;
|
|
75
|
-
return a && b ? order === "turnsAsc" ? left - right : right - left : 0;
|
|
76
|
-
}
|
|
77
49
|
async function copySessionText(text, clipboard = globalThis.navigator?.clipboard) {
|
|
78
50
|
if (typeof text !== "string" || !text) throw Object.assign(new Error("\u6CA1\u6709\u53EF\u590D\u5236\u7684\u5185\u5BB9"), { code: "copy.empty" });
|
|
79
51
|
if (!clipboard?.writeText) throw Object.assign(new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u526A\u8D34\u677F\uFF0C\u8BF7\u5728 HTTPS \u6216\u672C\u673A\u5730\u5740\u4E2D\u6253\u5F00\u9875\u9762"), { code: "copy.unavailable" });
|
|
@@ -85,7 +57,11 @@ async function copySessionText(text, clipboard = globalThis.navigator?.clipboard
|
|
|
85
57
|
}
|
|
86
58
|
function discoveryInvocations() {
|
|
87
59
|
const codec = (name, schema) => ({ mode: "strict", typeSymbol: `@michengai/dsh-archive-manager/types#${name}`, create: () => schema, schema });
|
|
88
|
-
const methods = [
|
|
60
|
+
const methods = [
|
|
61
|
+
["searchSessionContent", searchInputSchema, searchResultSchema],
|
|
62
|
+
["searchArchivedContent", searchInputSchema, searchResultSchema],
|
|
63
|
+
["previewArchivedSession", previewInputSchema, previewResultSchema]
|
|
64
|
+
];
|
|
89
65
|
return methods.map(([method, input, output]) => ({
|
|
90
66
|
id: `@michengai/dsh-archive-manager#workspaceRegistry/${method}`,
|
|
91
67
|
service: "workspaceRegistry",
|
|
@@ -155,9 +131,6 @@ function sliceWholeCharacters(text, start, end) {
|
|
|
155
131
|
if (splitsPair(end)) end--;
|
|
156
132
|
return text.slice(start, end);
|
|
157
133
|
}
|
|
158
|
-
function sessionDetailCandidates(ids, byId) {
|
|
159
|
-
return [...new Set(ids)].map((id2) => byId[id2] ?? { id: id2 });
|
|
160
|
-
}
|
|
161
134
|
function dayBoundary(value, nextDay = false) {
|
|
162
135
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) return NaN;
|
|
163
136
|
const [year, month, day] = value.split("-").map(Number);
|
|
@@ -192,62 +165,8 @@ async function searchArchiveBatches(ids, query, call, { signal, onProgress } = {
|
|
|
192
165
|
check();
|
|
193
166
|
return { items, failures };
|
|
194
167
|
}
|
|
195
|
-
function classifySessionError(error) {
|
|
196
|
-
const message = errorMessage(error);
|
|
197
|
-
const descriptions = {
|
|
198
|
-
"repair-frame": ["\u65E7\u7248\u4FEE\u590D\u751F\u6210\u7684\u538B\u7F29\u683C\u5F0F\u4E0D\u7B26\u5408\u5BBF\u4E3B\u8981\u6C42", "\u91CD\u65B0\u8BCA\u65AD\u53EF\u7EA0\u6B63\u538B\u7F29\u5E27\u683C\u5F0F\uFF0C\u539F\u59CB\u65E5\u5FD7\u4FDD\u6301\u4E0D\u53D8\u3002"],
|
|
199
|
-
"legacy-source": ["\u65E7\u7248\u6D88\u606F\u6765\u6E90\u4E0D\u53D7\u65B0\u7248 DSH \u652F\u6301", "\u8FD0\u884C\u8BCA\u65AD\uFF0C\u68C0\u67E5\u662F\u5426\u4E3A\u53EF\u8F6C\u6362\u7684\u65E7\u7248\u6765\u6E90\u3002"],
|
|
200
|
-
missing: ["\u4F1A\u8BDD\u65E5\u5FD7\u6216\u9644\u4EF6\u8DEF\u5F84\u4E0D\u5B58\u5728", "\u68C0\u67E5\u539F\u76EE\u5F55\u6216\u78C1\u76D8\u662F\u5426\u53EF\u7528\uFF1B\u7F3A\u5931\u6B63\u6587\u4E0D\u80FD\u901A\u8FC7\u91CD\u5EFA\u7F13\u5B58\u6062\u590D\u3002"],
|
|
201
|
-
permission: ["\u6CA1\u6709\u6743\u9650\u8BFB\u53D6\u4F1A\u8BDD\u6587\u4EF6", "\u68C0\u67E5\u76EE\u5F55\u8BBF\u95EE\u6743\u9650\u3001\u6587\u4EF6\u5360\u7528\u4E0E\u5B89\u5168\u8F6F\u4EF6\u9650\u5236\uFF0C\u518D\u91CD\u8BD5\u3002"],
|
|
202
|
-
corrupt: ["\u4F1A\u8BDD\u65E5\u5FD7\u53EF\u80FD\u635F\u574F\u6216\u672A\u5B8C\u6574\u5199\u5165", "\u4FDD\u7559\u73B0\u6709\u65E5\u5FD7\uFF0C\u68C0\u67E5\u78C1\u76D8\u548C\u539F\u59CB\u6587\u4EF6\uFF1B\u4E0D\u81EA\u52A8\u622A\u65AD\u6216\u5220\u9664\u6D88\u606F\u3002"],
|
|
203
|
-
unknown: ["\u4F1A\u8BDD\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6", "\u5148\u91CD\u8BD5\uFF1B\u4ECD\u5931\u8D25\u65F6\u5C55\u5F00\u6280\u672F\u8BE6\u60C5\uFF0C\u6309\u5177\u4F53\u9519\u8BEF\u68C0\u67E5\u5BBF\u4E3B\u517C\u5BB9\u6027\u3002"]
|
|
204
|
-
};
|
|
205
|
-
const codes = { ENOENT: "missing", EACCES: "permission", EPERM: "permission" };
|
|
206
|
-
const patterns = [
|
|
207
|
-
["repair-frame", /first frame is not exactly one header line/],
|
|
208
|
-
["legacy-source", /unclassified message source/],
|
|
209
|
-
["missing", /ENOENT|不存在|not found/i],
|
|
210
|
-
["permission", /EACCES|EPERM|permission/i],
|
|
211
|
-
["corrupt", /corrupt|JSON|incomplete|truncat|损坏|SessionFormatError/i]
|
|
212
|
-
];
|
|
213
|
-
const rawCode = errorCode(error);
|
|
214
|
-
const name = error && typeof error === "object" && "name" in error ? String(error.name ?? "") : "";
|
|
215
|
-
const explicit = typeof rawCode === "string" ? codes[rawCode] ?? rawCode : "";
|
|
216
|
-
if (Object.hasOwn(descriptions, explicit)) {
|
|
217
|
-
const [reason2, advice2] = descriptions[explicit];
|
|
218
|
-
return { code: explicit, reason: reason2, advice: advice2 };
|
|
219
|
-
}
|
|
220
|
-
const emptyToolCall = /requires toolCallId matching its tool source|tool call id requires a nonempty string/i;
|
|
221
|
-
if (emptyToolCall.test(message)) {
|
|
222
|
-
return {
|
|
223
|
-
code: "corrupt",
|
|
224
|
-
reason: "\u65E5\u5FD7\u5C3E\u90E8\u6709\u672A\u95ED\u5408\u7684\u5DE5\u5177\u8C03\u7528\uFF0C\u4E14 toolCallId \u4E3A\u7A7A",
|
|
225
|
-
advice: "\u4FDD\u7559\u73B0\u6709\u65E5\u5FD7\uFF0C\u68C0\u67E5\u78C1\u76D8\u548C\u539F\u59CB\u6587\u4EF6\uFF1B\u4E0D\u81EA\u52A8\u622A\u65AD\u6216\u6539\u5199\u65E5\u5FD7\u3002"
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
const namedCorrupt = name === "SessionFormatError" || name === "SessionPersistenceCorruptionError" ? "corrupt" : void 0;
|
|
229
|
-
const code = namedCorrupt ?? patterns.find(([, pattern]) => pattern.test(message))?.[0] ?? "unknown";
|
|
230
|
-
const [reason, advice] = descriptions[code];
|
|
231
|
-
return { code, reason, advice };
|
|
232
|
-
}
|
|
233
|
-
const repairInputSchema = { parse(input) {
|
|
234
|
-
const value = record(input);
|
|
235
|
-
const sessionId = id(value?.sessionId);
|
|
236
|
-
if (value?.token !== void 0 && (typeof value.token !== "string" || !/^[a-f0-9]{64}$/.test(value.token))) throw new TypeError("\u4FEE\u590D\u51ED\u636E\u65E0\u6548");
|
|
237
|
-
return { sessionId, ...value.token !== void 0 ? { token: value.token } : {} };
|
|
238
|
-
} };
|
|
239
|
-
const repairResultSchema = { parse(input) {
|
|
240
|
-
const value = record(input);
|
|
241
|
-
if (!value || typeof value.repairable !== "boolean" || typeof value.repaired !== "boolean") throw new TypeError("\u8BCA\u65AD\u7ED3\u679C\u65E0\u6548");
|
|
242
|
-
return { ...value.code !== void 0 ? { code: boundedString(value.code, 64) } : {}, sessionId: id(value.sessionId), repairable: value.repairable, repaired: value.repaired, reason: boundedString(value.reason, 1e3), advice: boundedString(value.advice, 1e3), token: boundedString(value.token ?? "", 64), count: sequence(value.count ?? 0) };
|
|
243
|
-
} };
|
|
244
168
|
export {
|
|
245
|
-
classifySessionError,
|
|
246
|
-
compareTurnCounts,
|
|
247
169
|
copySessionText,
|
|
248
|
-
countConversationTurns,
|
|
249
|
-
detailsInputSchema,
|
|
250
|
-
detailsResultSchema,
|
|
251
170
|
discoveryInvocations,
|
|
252
171
|
extractConversation,
|
|
253
172
|
findContentMatch,
|
|
@@ -256,11 +175,8 @@ export {
|
|
|
256
175
|
previewConversation,
|
|
257
176
|
previewInputSchema,
|
|
258
177
|
previewResultSchema,
|
|
259
|
-
repairInputSchema,
|
|
260
|
-
repairResultSchema,
|
|
261
178
|
searchArchiveBatches,
|
|
262
179
|
searchInputSchema,
|
|
263
180
|
searchResultSchema,
|
|
264
|
-
sessionDetailCandidates,
|
|
265
181
|
validUpdatedRange
|
|
266
182
|
};
|