dsh-session-mng 0.1.1 → 0.1.2
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/README.md +14 -2
- package/ROADMAP.md +21 -3
- package/client.js +156 -53
- package/docs/02-open-source-and-marketplace.md +14 -0
- package/docs/HANDOVER-2026-10-27.md +133 -0
- package/docs/PLAN-2026-10-27.md +2 -0
- package/docs/RELEASE-CHECKLIST-0.1.1.md +18 -5
- package/docs/RELEASE-CHECKLIST-0.1.2.md +31 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.2 — 2026-10-27(unreleased)
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- 默认隐藏空会话(`blank: true`):这类会话本来就不出现在侧栏会话列表;现在「会话管理」默认也不显示,可用「显示空会话」临时查看。
|
|
8
|
+
- 「清理空会话(N)」:批量清理**已归档且可删除**的空会话,仍先弹出删除范围确认;未归档空会话会提示先归档。
|
|
9
|
+
- 全部/活跃/已归档 tab 计数与隐藏空会话后的可见列表一致;总览行显示「已隐藏 N 个空会话」。
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- 删除范围确认改为**模态对话框**:内容区独立滚动,底部「我已了解」勾选与「确认彻底删除 / 取消」固定可见,不再随列表滚走。
|
|
14
|
+
- 删除范围弹窗支持点击遮罩取消、Esc 取消;加载/错误状态仍显示取消按钮。
|
|
15
|
+
|
|
3
16
|
## 0.1.1 — 2026-10-27
|
|
4
17
|
|
|
5
18
|
### Changed
|
package/README.md
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
- **统一会话总览**:按工作区分组列出当前 profile 的全部会话(活跃 + 已归档)。显示标题、路径、会话 id、大小、最后活动时间、运行/已打开/已归档/已置顶/子会话标记;支持搜索、工作区筛选、排序、刷新、批量选择。
|
|
18
18
|
- **工作区优先 + 分页**:会话数 >100 时默认折叠工作区;每个工作区默认 50 条,「加载更多」继续展开;搜索自动展开命中工作区。过滤工具栏和批量条整体吸顶。
|
|
19
19
|
- **选择跟随可见集**:切换筛选/折叠/搜索/刷新后,隐藏会话自动取消选择;`全选当前列表` 只作用于当前筛选与已展开的工作区。
|
|
20
|
+
- **空会话默认隐藏**:侧栏本来就不显示的 `blank` 会话,会话管理默认也不显示;勾选「显示空会话」才出现。提供「清理空会话(N)」快速清理已归档空会话。
|
|
21
|
+
- **删除范围模态确认**:范围内容在弹窗内独立滚动,底部勾选与确认/取消按钮固定可见;支持遮罩点击/Esc 取消。
|
|
20
22
|
- **生成标题**:选中任意会话(**包括已归档的冷会话**),让模型总结整段对话,给出可编辑的标题提案;**确认后才写入**。活跃会话走官方 `sessionTitle.rename`,冷会话按官方 `session/title` 事件形状追加,不需要恢复会话。
|
|
21
23
|
- **归档 / 恢复**:调用官方 `workspaceRegistry.archiveSession` / `unarchiveSession`。运行中的会话先提示,用户二次确认后才停止并归档;恢复后回到原工作区原位置。
|
|
22
24
|
- **跨工作区移动**:把冷会话真正迁移到目标工作区——改写会话日志 header 的 `cwd`、把日志目录迁到目标项目目录、同步 workspace 账本。SessionId、归档状态、pin 状态不变,事件字节不变。
|
|
@@ -54,7 +56,7 @@ dsh plugin --profile <profile> add link:/绝对路径/dsh-session-mng
|
|
|
54
56
|
|
|
55
57
|
Host 半是进程内模块:装完如果看不到页面,重启一次 dsh/应用再刷新页面;Client 半刷新页面即可。
|
|
56
58
|
|
|
57
|
-
>
|
|
59
|
+
> 市场状态:awesome-dsh-plugin 收录 PR [#9672](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin/pull/9672) 的 `check` 已通过;`Submission gate` 目前只差仓库满 1 天(约 2026-10-28 00:44 Asia/Shanghai 自动重跑),无需重新提交。合并后 dshmarket 读取同一份目录,卡片版本随 npm 显示 `0.1.1`。
|
|
58
60
|
|
|
59
61
|
## 使用
|
|
60
62
|
|
|
@@ -94,6 +96,7 @@ Host route (lib/api.js) ──► service (lib/service.js)
|
|
|
94
96
|
| 会话后端 | 移动/删除只支持本地 JSONL 后端(`sessionPersistence.locate`);其他后端仍可用总览/标题/归档/恢复 |
|
|
95
97
|
| 官方依赖 | 无 runtime 依赖;只使用 `ctx` 服务 |
|
|
96
98
|
| 已知限制 | 已打开(live)会话不能移动或彻底删除,重启 DSH 后重试;有子代理后代的会话不能单独移动;子会话不出现在主列表(可勾选「显示子会话」查看) |
|
|
99
|
+
| 规模限制 | 0.1.1 的折叠/分页只在客户端压 DOM,`state` 仍一次拉全量(202 条约 103 KB;10000 条约 5 MB)。Host 侧 overview + paged sessions 是 0.2.0 的主任务 |
|
|
97
100
|
|
|
98
101
|
### 版本敏感点(请读)
|
|
99
102
|
|
|
@@ -136,14 +139,23 @@ node --check index.js client.js lib/*.js
|
|
|
136
139
|
npm --cache /tmp/dsh-npm-cache pack --dry-run
|
|
137
140
|
```
|
|
138
141
|
|
|
139
|
-
|
|
142
|
+
实机验收:安装到 `desktop` profile → 确认 `settings.section` 出现 `session-mng-section` → 用**一次性测试会话**验证标题/归档/恢复/移动/删除 → 清理测试数据。0.1.1 的列表验收见 `docs/RELEASE-CHECKLIST-0.1.1.md`。
|
|
143
|
+
|
|
144
|
+
## 当前状态与下一步
|
|
145
|
+
|
|
146
|
+
- `0.1.1` 已发布到 npm / GitHub / Release;26 个测试全绿,31 个文件。
|
|
147
|
+
- `0.1.2`(空会话清理 + 删除范围弹窗)已在工作区实现,待实机测试/发布。
|
|
148
|
+
- 市场 PR [#9672](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin/pull/9672) 等 1 天仓库年龄 gate,之后等维护者合并。
|
|
149
|
+
- 下一项主任务:**0.2.0 Host 侧 overview + 分页 sessions**,为 1000–10000 条会话设计;详细任务、验收标准、环境坑见 [接手说明](docs/HANDOVER-2026-10-27.md)。
|
|
140
150
|
|
|
141
151
|
## 文档索引
|
|
142
152
|
|
|
153
|
+
- [接手说明(下一步任务)](docs/HANDOVER-2026-10-27.md)
|
|
143
154
|
- [实施计划(批准时原样归档)](docs/PLAN-2026-10-26.md)
|
|
144
155
|
- [0.1.0 发布检查清单](docs/RELEASE-CHECKLIST-0.1.0.md)
|
|
145
156
|
- [0.1.1 实施计划](docs/PLAN-2026-10-27.md)
|
|
146
157
|
- [0.1.1 发布检查清单](docs/RELEASE-CHECKLIST-0.1.1.md)
|
|
158
|
+
- [0.1.2 发布检查清单(待发布)](docs/RELEASE-CHECKLIST-0.1.2.md)
|
|
147
159
|
- [设计与实现说明](docs/01-design.md)
|
|
148
160
|
- [开源、发 npm 与市场收录记录](docs/02-open-source-and-marketplace.md)
|
|
149
161
|
- [路线图](ROADMAP.md)
|
package/ROADMAP.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Roadmap
|
|
2
2
|
|
|
3
|
+
> 当前:`0.1.1` 已发布(npm latest / tag `v0.1.1` / Release)。市场 PR [#9672](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin/pull/9672) 的 `check` 已过,只差仓库 1 天年龄 gate(约 2026-10-28 00:44 Asia/Shanghai 自动重跑)。下一项主任务是 0.2.0 的 Host 分页;详细接手任务见 [docs/HANDOVER-2026-10-27.md](docs/HANDOVER-2026-10-27.md)。
|
|
4
|
+
|
|
3
5
|
## 0.1.0 — delivered
|
|
4
6
|
|
|
5
7
|
- 统一会话总览(活跃 + 已归档,工作区分组,搜索/筛选/排序,日志大小)。
|
|
@@ -17,10 +19,26 @@
|
|
|
17
19
|
- 选择集裁剪到当前筛选与展开可见集;批量操作不触碰隐藏会话。
|
|
18
20
|
- 批量移动提示区分 live 与一般不可移动项。
|
|
19
21
|
|
|
20
|
-
## 0.2
|
|
22
|
+
## 0.1.2 — in progress
|
|
23
|
+
|
|
24
|
+
- 空会话默认隐藏 + 「显示空会话」开关;tab 计数与可见列表一致。
|
|
25
|
+
- 「清理空会话(N)」批量清理已归档空会话,复用删除范围预览/确认。
|
|
26
|
+
- 删除范围确认改为模态框,内容独立滚动、底部确认区固定,支持遮罩/Esc 取消。
|
|
27
|
+
|
|
28
|
+
## 0.2.0 — next (planned)
|
|
29
|
+
|
|
30
|
+
首要目标:真正支撑 1000–10000 条会话,不再首屏拉全量 `state`。实施前先写 `docs/PLAN-2026-10-28.md` 并获批准。
|
|
31
|
+
|
|
32
|
+
- `GET /session-mng/api/overview`:只返回工作区计数/大小/归档数、totals、capabilities、orphans;不读全部标题/日志。
|
|
33
|
+
- `GET /session-mng/api/sessions`:按 `workspaceId/tab/offset/limit/query/sort` 分页;只对当前页 id 读标题/大小;返回 `hasMore`。
|
|
34
|
+
- 未分组会话懒加载 + 短 TTL 缓存;全局搜索先只读验证宿主 search 是否覆盖标题。
|
|
35
|
+
- Client:overview 首屏 → 工作区展开时取第一页 → 加载更多;保留 sticky、选择裁剪、搜索自动展开。
|
|
36
|
+
- 兼容:保留 `/state` 给 0.1.x 客户端;Host 同时提供新旧接口。
|
|
37
|
+
- 验收:合成 10k 数据首屏不返回 session rows;单页 ≤50 行;不触发全量 `sessionController.list`;现有 26 测试 + 新增分页/overview/search 测试。
|
|
38
|
+
- 详细接口建议、验收与坑:[docs/HANDOVER-2026-10-27.md](docs/HANDOVER-2026-10-27.md)。
|
|
39
|
+
|
|
40
|
+
## Later candidates
|
|
21
41
|
|
|
22
|
-
- Host 侧 overview + paged sessions 接口:首屏只取工作区计数,按工作区懒加载 50 条,真正支撑 1000–10000 条会话。
|
|
23
|
-
- 未分组会话懒加载 + 短缓存;全局搜索复用宿主索引。
|
|
24
42
|
- 侧栏会话「...」菜单快捷入口(生成标题 / 会话管理详情),复用同一套 Host 操作。
|
|
25
43
|
- 内容全文搜索(复用 `sessionQuery.searchSessions` / `searchEvents`),不只按标题/路径/id。
|
|
26
44
|
- 导出所选会话为 Markdown / JSON(删除前的安全网;批量)。
|
package/client.js
CHANGED
|
@@ -44,6 +44,11 @@ window.__ModuleLoader__.load({
|
|
|
44
44
|
sortSize: '大小',
|
|
45
45
|
sortTitle: '标题',
|
|
46
46
|
showSubagents: '显示子会话',
|
|
47
|
+
showBlank: '显示空会话',
|
|
48
|
+
cleanupBlank: '清理空会话({n})',
|
|
49
|
+
cleanupBlankHint: '批量删除已归档的空会话;未归档的空会话需先归档。',
|
|
50
|
+
blankActiveHint: '另有 {n} 个未归档空会话,归档后才能清理。',
|
|
51
|
+
hiddenBlankCount: '已隐藏 {n} 个空会话',
|
|
47
52
|
selectAll: '全选当前列表',
|
|
48
53
|
expandAll: '展开全部',
|
|
49
54
|
collapseAll: '收起全部',
|
|
@@ -192,6 +197,11 @@ window.__ModuleLoader__.load({
|
|
|
192
197
|
sortSize: 'Size',
|
|
193
198
|
sortTitle: 'Title',
|
|
194
199
|
showSubagents: 'Show subagent sessions',
|
|
200
|
+
showBlank: 'Show empty sessions',
|
|
201
|
+
cleanupBlank: 'Clean up empty sessions ({n})',
|
|
202
|
+
cleanupBlankHint: 'Permanently delete archived empty sessions; unarchived empty sessions must be archived first.',
|
|
203
|
+
blankActiveHint: '{n} unarchived empty sessions must be archived before cleanup.',
|
|
204
|
+
hiddenBlankCount: '{n} empty sessions hidden',
|
|
195
205
|
selectAll: 'Select all shown',
|
|
196
206
|
expandAll: 'Expand all',
|
|
197
207
|
collapseAll: 'Collapse all',
|
|
@@ -430,6 +440,22 @@ window.__ModuleLoader__.load({
|
|
|
430
440
|
.dsm-scope-row .dsm-mono{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
431
441
|
.dsm-danger-box{border:1px solid var(--dsw-alias-state-error-primary);border-radius:8px;padding:10px;background:var(--dsw-alias-bg-layer-1)}
|
|
432
442
|
.dsm-danger-box h3{color:var(--dsw-alias-state-error-primary)}
|
|
443
|
+
.dsm-scope-overlay{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;
|
|
444
|
+
padding:20px;background:rgba(0,0,0,.58)}
|
|
445
|
+
.dsm-scope-dialog{display:flex;flex-direction:column;width:min(660px,100%);max-height:min(82vh,760px);
|
|
446
|
+
border:1px solid var(--dsw-alias-state-error-primary);border-radius:10px;overflow:hidden;
|
|
447
|
+
background:var(--dsw-alias-bg-layer-2);box-shadow:0 24px 70px rgba(0,0,0,.5)}
|
|
448
|
+
.dsm-scope-head{display:flex;align-items:center;justify-content:space-between;gap:10px;
|
|
449
|
+
padding:11px 14px;border-bottom:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1)}
|
|
450
|
+
.dsm-scope-head h3{margin:0;font-size:13px;line-height:18px;color:var(--dsw-alias-state-error-primary)}
|
|
451
|
+
.dsm-scope-body{flex:1 1 auto;min-height:0;overflow:auto;padding:12px 14px}
|
|
452
|
+
.dsm-scope-foot{display:flex;flex-direction:column;gap:8px;padding:10px 14px;
|
|
453
|
+
border-top:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1)}
|
|
454
|
+
.dsm-scope-dialog .dsm-scope-list{max-height:none;overflow:visible;margin:8px 0}
|
|
455
|
+
@media (max-width:640px){
|
|
456
|
+
.dsm-scope-overlay{padding:10px}
|
|
457
|
+
.dsm-scope-dialog{max-height:92vh}
|
|
458
|
+
}
|
|
433
459
|
.dsm-footer{font-size:11px;line-height:17px;color:var(--dsw-alias-label-secondary)}
|
|
434
460
|
.dsm-spin{display:inline-block;width:12px;height:12px;border:2px solid var(--dsw-alias-border-l2);
|
|
435
461
|
border-top-color:var(--dsw-alias-brand-primary);border-radius:50%;animation:dsm-spin .8s linear infinite;vertical-align:-2px}
|
|
@@ -919,6 +945,7 @@ window.__ModuleLoader__.load({
|
|
|
919
945
|
React.useEffect(() => {
|
|
920
946
|
const controller = new AbortController()
|
|
921
947
|
setPhase('loading')
|
|
948
|
+
setChecked(false)
|
|
922
949
|
post('delete/preview', { sessionIds: ids }, controller.signal)
|
|
923
950
|
.then((value) => {
|
|
924
951
|
if (controller.signal.aborted) return
|
|
@@ -933,43 +960,86 @@ window.__ModuleLoader__.load({
|
|
|
933
960
|
return () => controller.abort()
|
|
934
961
|
}, [idsKey, t])
|
|
935
962
|
|
|
963
|
+
React.useEffect(() => {
|
|
964
|
+
const onKeyDown = (event) => {
|
|
965
|
+
if (event.key !== 'Escape') return
|
|
966
|
+
event.preventDefault()
|
|
967
|
+
event.stopPropagation()
|
|
968
|
+
if (busy !== true) onCancel()
|
|
969
|
+
}
|
|
970
|
+
document.addEventListener('keydown', onKeyDown, true)
|
|
971
|
+
return () => document.removeEventListener('keydown', onKeyDown, true)
|
|
972
|
+
}, [busy, onCancel])
|
|
973
|
+
|
|
936
974
|
const rows = preview?.sessions ?? []
|
|
937
975
|
const blocked = rows.some((row) => row.live || row.running)
|
|
976
|
+
const ready = phase === 'ready' && preview !== null
|
|
938
977
|
return h(
|
|
939
978
|
'div',
|
|
940
|
-
{
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
979
|
+
{
|
|
980
|
+
className: 'dsm-scope-overlay',
|
|
981
|
+
onMouseDown: (event) => {
|
|
982
|
+
if (event.target === event.currentTarget && busy !== true) onCancel()
|
|
983
|
+
},
|
|
984
|
+
},
|
|
985
|
+
h(
|
|
986
|
+
'div',
|
|
987
|
+
{
|
|
988
|
+
className: 'dsm-scope-dialog',
|
|
989
|
+
role: 'dialog',
|
|
990
|
+
'aria-modal': 'true',
|
|
991
|
+
'aria-label': t('deleteScope'),
|
|
992
|
+
},
|
|
993
|
+
h(
|
|
994
|
+
'div',
|
|
995
|
+
{ className: 'dsm-scope-head' },
|
|
996
|
+
h('h3', null, t('deleteScope')),
|
|
997
|
+
h('button', {
|
|
998
|
+
type: 'button',
|
|
999
|
+
className: 'dsm-btn ghost',
|
|
1000
|
+
'aria-label': t('close'),
|
|
1001
|
+
disabled: busy,
|
|
1002
|
+
onClick: onCancel,
|
|
1003
|
+
}, '×'),
|
|
1004
|
+
),
|
|
1005
|
+
h(
|
|
1006
|
+
'div',
|
|
1007
|
+
{ className: 'dsm-scope-body' },
|
|
1008
|
+
h('p', { className: 'dsm-hint', style: { margin: '0 0 8px' } }, t('deleteHint')),
|
|
1009
|
+
phase === 'loading'
|
|
1010
|
+
? h('p', { className: 'dsm-hint' }, t('deletePreviewLoading'))
|
|
1011
|
+
: phase === 'error'
|
|
1012
|
+
? h('p', { className: 'dsm-error' }, error)
|
|
1013
|
+
: h(
|
|
1014
|
+
React.Fragment,
|
|
1015
|
+
null,
|
|
1016
|
+
h('div', { className: 'dsm-hint' },
|
|
1017
|
+
`${t('deleteRoots')}: ${preview?.roots?.length ?? 0} · ${t('deleteDescendants')}: ${preview?.descendantCount ?? 0} · ${t('deleteTotalSize', { size: formatBytes(preview?.totalBytes ?? 0) })}`,
|
|
965
1018
|
),
|
|
1019
|
+
h('div', { className: 'dsm-scope-list' },
|
|
1020
|
+
rows.map((row) =>
|
|
1021
|
+
h(
|
|
1022
|
+
'div',
|
|
1023
|
+
{ key: row.id, className: 'dsm-scope-row' },
|
|
1024
|
+
h('span', { className: 'dsm-badge' }, row.descendant ? t('scopeChild') : t('scopeRoot')),
|
|
1025
|
+
h('span', { className: 'dsm-mono', title: row.dir ?? row.id }, row.id),
|
|
1026
|
+
row.live ? h(Badge, { tone: 'brand' }, t('liveBadge')) : null,
|
|
1027
|
+
row.running ? h(Badge, { tone: 'run' }, t('running')) : null,
|
|
1028
|
+
row.missing ? h(Badge, { tone: 'warn' }, t('missingDir')) : null,
|
|
1029
|
+
row.readable === false ? h(Badge, { tone: 'warn' }, t('unreadable')) : null,
|
|
1030
|
+
h('span', { style: { marginLeft: 'auto' } }, formatBytes(row.bytes)),
|
|
1031
|
+
),
|
|
1032
|
+
),
|
|
1033
|
+
),
|
|
1034
|
+
h('p', { className: 'dsm-hint', style: { margin: '0 0 6px' } }, t('deleteCascadeNote')),
|
|
1035
|
+
blocked ? h('p', { className: 'dsm-error' }, t('deleteLiveHint')) : null,
|
|
966
1036
|
),
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1037
|
+
),
|
|
1038
|
+
h(
|
|
1039
|
+
'div',
|
|
1040
|
+
{ className: 'dsm-scope-foot' },
|
|
1041
|
+
ready
|
|
1042
|
+
? h('label', { className: 'dsm-check' },
|
|
973
1043
|
h('input', {
|
|
974
1044
|
type: 'checkbox',
|
|
975
1045
|
checked,
|
|
@@ -977,20 +1047,22 @@ window.__ModuleLoader__.load({
|
|
|
977
1047
|
onChange: (event) => setChecked(event.target.checked),
|
|
978
1048
|
}),
|
|
979
1049
|
t('deleteConfirmCheck'),
|
|
980
|
-
)
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1050
|
+
)
|
|
1051
|
+
: null,
|
|
1052
|
+
h(
|
|
1053
|
+
'div',
|
|
1054
|
+
{ className: 'dsm-actions' },
|
|
1055
|
+
h('button', {
|
|
1056
|
+
type: 'button',
|
|
1057
|
+
className: 'dsm-btn danger',
|
|
1058
|
+
disabled: busy || ready !== true || blocked || checked !== true,
|
|
1059
|
+
onClick: () => onConfirmed(ids),
|
|
1060
|
+
}, busy ? t('deleting') : t('deleteConfirm')),
|
|
1061
|
+
h('button', { type: 'button', className: 'dsm-btn ghost', disabled: busy, onClick: onCancel }, t('cancel')),
|
|
1062
|
+
blocked ? h('span', { className: 'dsm-hint' }, t('liveHint')) : null,
|
|
1063
|
+
),
|
|
1064
|
+
),
|
|
1065
|
+
),
|
|
994
1066
|
)
|
|
995
1067
|
}
|
|
996
1068
|
|
|
@@ -1153,7 +1225,7 @@ window.__ModuleLoader__.load({
|
|
|
1153
1225
|
* Derive the filtered / grouped / rendered view for the list.
|
|
1154
1226
|
* Pure so the selection-pruning effect can use it before the loading guard.
|
|
1155
1227
|
*/
|
|
1156
|
-
function computeView({ state, tab, workspaceFilter, query, sort, expanded, defaultExpanded, limits }) {
|
|
1228
|
+
function computeView({ state, tab, workspaceFilter, query, sort, expanded, defaultExpanded, limits, showBlank }) {
|
|
1157
1229
|
const rows = state?.sessions ?? []
|
|
1158
1230
|
const workspaceOrder = state?.workspaces ?? []
|
|
1159
1231
|
const text = query.trim().toLowerCase()
|
|
@@ -1163,6 +1235,7 @@ window.__ModuleLoader__.load({
|
|
|
1163
1235
|
if (tab === 'archived' && !row.archived) return false
|
|
1164
1236
|
if (workspaceFilter === 'ungrouped' && row.workspaceId !== null) return false
|
|
1165
1237
|
if (workspaceFilter !== 'all' && workspaceFilter !== 'ungrouped' && row.workspaceId !== workspaceFilter) return false
|
|
1238
|
+
if (showBlank !== true && row.blank === true) return false
|
|
1166
1239
|
if (filtering) {
|
|
1167
1240
|
const haystack = `${row.title}\n${row.cwd}\n${row.id}`.toLowerCase()
|
|
1168
1241
|
if (!haystack.includes(text)) return false
|
|
@@ -1233,6 +1306,7 @@ window.__ModuleLoader__.load({
|
|
|
1233
1306
|
const [bulkTarget, setBulkTarget] = React.useState('')
|
|
1234
1307
|
const [expanded, setExpanded] = React.useState(null)
|
|
1235
1308
|
const [limits, setLimits] = React.useState({})
|
|
1309
|
+
const [showBlank, setShowBlank] = React.useState(false)
|
|
1236
1310
|
const abortRef = React.useRef(null)
|
|
1237
1311
|
const searchRef = React.useRef(null)
|
|
1238
1312
|
const listScroll = React.useRef(0)
|
|
@@ -1298,6 +1372,7 @@ window.__ModuleLoader__.load({
|
|
|
1298
1372
|
if (selectedId === null) return undefined
|
|
1299
1373
|
const onKeyDown = (event) => {
|
|
1300
1374
|
if (event.key === 'Escape') {
|
|
1375
|
+
if (document.querySelector('.dsm-scope-overlay') !== null) return
|
|
1301
1376
|
event.stopPropagation()
|
|
1302
1377
|
backToList()
|
|
1303
1378
|
}
|
|
@@ -1308,13 +1383,13 @@ window.__ModuleLoader__.load({
|
|
|
1308
1383
|
|
|
1309
1384
|
React.useEffect(() => {
|
|
1310
1385
|
setLimits({})
|
|
1311
|
-
}, [tab, workspaceFilter, query, includeSubagents])
|
|
1386
|
+
}, [tab, workspaceFilter, query, includeSubagents, showBlank])
|
|
1312
1387
|
|
|
1313
1388
|
const rows = state?.sessions ?? []
|
|
1314
1389
|
const defaultExpanded = (state?.totals?.all ?? 0) <= DEFAULT_COLLAPSE_AFTER
|
|
1315
1390
|
const view = React.useMemo(
|
|
1316
|
-
() => computeView({ state, tab, workspaceFilter, query, sort, expanded, defaultExpanded, limits }),
|
|
1317
|
-
[state, tab, workspaceFilter, query, sort, expanded, defaultExpanded, limits],
|
|
1391
|
+
() => computeView({ state, tab, workspaceFilter, query, sort, expanded, defaultExpanded, limits, showBlank }),
|
|
1392
|
+
[state, tab, workspaceFilter, query, sort, expanded, defaultExpanded, limits, showBlank],
|
|
1318
1393
|
)
|
|
1319
1394
|
const viewKey = React.useMemo(
|
|
1320
1395
|
() => [
|
|
@@ -1323,10 +1398,11 @@ window.__ModuleLoader__.load({
|
|
|
1323
1398
|
workspaceFilter,
|
|
1324
1399
|
query,
|
|
1325
1400
|
includeSubagents ? 1 : 0,
|
|
1401
|
+
showBlank ? 1 : 0,
|
|
1326
1402
|
defaultExpanded ? 1 : 0,
|
|
1327
1403
|
expanded === null ? 'auto' : [...expanded].sort().join(','),
|
|
1328
1404
|
].join('|'),
|
|
1329
|
-
[state?.generatedAt, tab, workspaceFilter, query, includeSubagents, defaultExpanded, expanded],
|
|
1405
|
+
[state?.generatedAt, tab, workspaceFilter, query, includeSubagents, showBlank, defaultExpanded, expanded],
|
|
1330
1406
|
)
|
|
1331
1407
|
React.useEffect(() => {
|
|
1332
1408
|
setSelected((previous) => {
|
|
@@ -1455,10 +1531,14 @@ window.__ModuleLoader__.load({
|
|
|
1455
1531
|
return h('div', { className: 'dsm-page' }, h('p', { className: 'dsm-hint' }, h(Spinner, { t, label: t('loading') })))
|
|
1456
1532
|
}
|
|
1457
1533
|
|
|
1534
|
+
const rowsForTabs = rows.filter((row) => showBlank || row.blank !== true)
|
|
1535
|
+
const blankRows = rows.filter((row) => row.blank === true)
|
|
1536
|
+
const blankArchivedRows = blankRows.filter((row) => row.archived === true && row.can?.delete === true)
|
|
1537
|
+
const blankActiveCount = blankRows.filter((row) => row.archived !== true || row.can?.delete !== true).length
|
|
1458
1538
|
const tabs = [
|
|
1459
|
-
{ key: 'all', label: t('tabAll'), count:
|
|
1460
|
-
{ key: 'active', label: t('tabActive'), count:
|
|
1461
|
-
{ key: 'archived', label: t('tabArchived'), count:
|
|
1539
|
+
{ key: 'all', label: t('tabAll'), count: rowsForTabs.length },
|
|
1540
|
+
{ key: 'active', label: t('tabActive'), count: rowsForTabs.filter((row) => !row.archived).length },
|
|
1541
|
+
{ key: 'archived', label: t('tabArchived'), count: rowsForTabs.filter((row) => row.archived).length },
|
|
1462
1542
|
]
|
|
1463
1543
|
const visibleAllSelected = view.visibleRows.length > 0 && view.visibleRows.every((row) => selected.has(row.id))
|
|
1464
1544
|
const selectedRows = view.visibleRows.filter((row) => selected.has(row.id))
|
|
@@ -1564,9 +1644,24 @@ window.__ModuleLoader__.load({
|
|
|
1564
1644
|
archived: state.totals.archived,
|
|
1565
1645
|
size: formatBytes(state.totals.bytes),
|
|
1566
1646
|
}),
|
|
1647
|
+
blankRows.length > 0 && !showBlank
|
|
1648
|
+
? ` · ${t('hiddenBlankCount', { n: blankRows.length })}`
|
|
1649
|
+
: '',
|
|
1567
1650
|
),
|
|
1651
|
+
blankActiveCount > 0 && showBlank
|
|
1652
|
+
? h('p', { className: 'dsm-hint' }, t('blankActiveHint', { n: blankActiveCount }))
|
|
1653
|
+
: null,
|
|
1568
1654
|
),
|
|
1569
1655
|
h('div', { className: 'dsm-head-actions' },
|
|
1656
|
+
blankArchivedRows.length > 0
|
|
1657
|
+
? h('button', {
|
|
1658
|
+
type: 'button',
|
|
1659
|
+
className: 'dsm-btn',
|
|
1660
|
+
disabled: busy,
|
|
1661
|
+
title: `${t('cleanupBlankHint')}${blankActiveCount > 0 ? ` ${t('blankActiveHint', { n: blankActiveCount })}` : ''}`,
|
|
1662
|
+
onClick: () => setBulkDeleteIds(blankArchivedRows.map((row) => row.id)),
|
|
1663
|
+
}, t('cleanupBlank', { n: blankArchivedRows.length }))
|
|
1664
|
+
: null,
|
|
1570
1665
|
h('button', { type: 'button', className: 'dsm-btn', disabled: busy, onClick: () => void load({ silent: true }) },
|
|
1571
1666
|
busy ? h(Spinner, { t, label: t('working') }) : t('refresh')),
|
|
1572
1667
|
),
|
|
@@ -1639,6 +1734,14 @@ window.__ModuleLoader__.load({
|
|
|
1639
1734
|
}),
|
|
1640
1735
|
t('showSubagents'),
|
|
1641
1736
|
),
|
|
1737
|
+
h('label', { className: 'dsm-check' },
|
|
1738
|
+
h('input', {
|
|
1739
|
+
type: 'checkbox',
|
|
1740
|
+
checked: showBlank,
|
|
1741
|
+
onChange: (event) => setShowBlank(event.target.checked),
|
|
1742
|
+
}),
|
|
1743
|
+
t('showBlank'),
|
|
1744
|
+
),
|
|
1642
1745
|
),
|
|
1643
1746
|
view.visibleRows.length > 0
|
|
1644
1747
|
? h(
|
|
@@ -118,3 +118,17 @@ curl -s https://awesome-dsh-plugin.com/plugins.json | grep -i session-mng
|
|
|
118
118
|
- [ ] PR 编号 / 合并状态 / CI 结果
|
|
119
119
|
- [ ] dshmarket 卡片截图或文本记录
|
|
120
120
|
- [ ] `docs/PLAN-2026-10-26.md` 末尾追加「事后差异(补记)」
|
|
121
|
+
|
|
122
|
+
## 7. 0.1.1 更新发布(2026-10-27)
|
|
123
|
+
|
|
124
|
+
0.1.1 是客户端可用性修复(工作区优先/分页、sticky、选择裁剪、控件视觉),Host API 未变,marketplace 条目不需要改 YAML。
|
|
125
|
+
|
|
126
|
+
- 本地提交:`cea99f9 fix: align sticky surface and enlarge list controls`(功能提交 `d36e725`)。
|
|
127
|
+
- `npm publish`:`dsh-session-mng@0.1.1`,31 个文件,tarball 560.7 kB / unpacked 767.4 kB;发布后约 90 秒 packument 出现 0.1.1,`latest` = 0.1.1,版本端点 200。
|
|
128
|
+
- Git:main 已 push;tag `v0.1.1`;GitHub Release 见仓库 Releases。
|
|
129
|
+
- marketplace:PR [#9672](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin/pull/9672) 不变;`check` 已通过,`Submission gate` 仅因仓库 0.0 天(需要 1 天)失败;该检查会自动重跑,约 24h 后转绿,不需要重新提交。
|
|
130
|
+
- Release:https://github.com/ZilongYang/dsh-session-mng/releases/tag/v0.1.1
|
|
131
|
+
|
|
132
|
+
## 8. 接手
|
|
133
|
+
|
|
134
|
+
下一步市场验证与 0.2.0 任务见 [HANDOVER-2026-10-27.md](HANDOVER-2026-10-27.md)。
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# dsh-session-mng 接手说明(2026-10-27)
|
|
2
|
+
|
|
3
|
+
> 面向下一个接手的人/会话。先读这一页,再按链接进入详细文档。当前代码在 `main`,工作区干净。
|
|
4
|
+
|
|
5
|
+
## 1. 当前状态
|
|
6
|
+
|
|
7
|
+
| 项 | 值 |
|
|
8
|
+
|---|---|
|
|
9
|
+
| 版本 | `0.1.1`(npm `latest`) |
|
|
10
|
+
| npm | https://www.npmjs.com/package/dsh-session-mng |
|
|
11
|
+
| GitHub | https://github.com/ZilongYang/dsh-session-mng |
|
|
12
|
+
| Release | https://github.com/ZilongYang/dsh-session-mng/releases/tag/v0.1.1 |
|
|
13
|
+
| 当前 main | 发布代码/功能提交 `d36e725`、`cea99f9`;交接后的文档提交以远端 `main` 为准 |
|
|
14
|
+
| Tag | `v0.1.1` → `1b6a07f` |
|
|
15
|
+
| 测试 | `node --test` 26 个全绿 |
|
|
16
|
+
| 包内容 | `npm pack` 31 个文件 / 560.8 kB;发布 tarball 560.7 kB |
|
|
17
|
+
| 本地安装 | 已作为 symlink 安装到 Desktop `desktop` profile;改 client 后刷新页面即可,Host 改动需重启 DSH |
|
|
18
|
+
| 市场 PR | awesome-dsh-plugin [#9672](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin/pull/9672),open |
|
|
19
|
+
|
|
20
|
+
### 市场 PR 的真实状态
|
|
21
|
+
|
|
22
|
+
- 条目文件:`data/plugins/ZilongYang__dsh-session-mng.yml`,只新增 1 个文件;分支 `add-dsh-session-mng`(fork `ZilongYang/awesome-dsh-plugin`)。
|
|
23
|
+
- CI:`check` **已通过**;`Submission gate` 唯一失败项是**仓库 0.0 天,要求满 1 天**。
|
|
24
|
+
- Gate 原文:`repository is 0.0 days old (needs 1) — this check re-runs by itself and should clear in about 24h. No need to resubmit, push, or close and reopen.`
|
|
25
|
+
- 预计自动转绿:仓库创建于 `2026-10-26T16:44:42Z`,满 1 天约为 **2026-10-27T16:44Z / 2026-10-28 00:44 Asia/Shanghai**。
|
|
26
|
+
- **不要**重新提交 PR 或关闭重开;gate 自动重跑。转绿后等维护者合并。
|
|
27
|
+
- 合并后 dshmarket/awesome 目录才会出现;市场卡片读取 npm 版本,当前应显示 `0.1.1`。验证:`curl -s https://awesome-dsh-plugin.com/plugins.json | grep -i session-mng`,以及在 dshmarket 搜 `dsh-session-mng`。
|
|
28
|
+
|
|
29
|
+
## 2. 代码地图
|
|
30
|
+
|
|
31
|
+
| 文件 | 职责 / 接手要点 |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `index.js` | Host 入口、inject、幂等挂载 `/session-mng/api` |
|
|
34
|
+
| `lib/api.js` | 路由、64 KiB body 上限、错误信封;**新增加分页接口从这里开始** |
|
|
35
|
+
| `lib/fence.js` | loopback / trustedHosts / Origin 围栏 |
|
|
36
|
+
| `lib/service.js` | 操作层;state / title / archive / delete / move |
|
|
37
|
+
| `lib/state.js` | 总览组装;0.2.0 的 overview/page 应从这里拆分 |
|
|
38
|
+
| `lib/title.js` | 整段会话标题、模型路由、清洗/截断 |
|
|
39
|
+
| `lib/store-jsonl.js` | header、zstd frame、目录复制/事务/回滚 |
|
|
40
|
+
| `lib/workspace-sync.js` | 移动后的 registry 缓存对账;删除后的账本清理 |
|
|
41
|
+
| `client.js` | 设置页单文件 UI;列表逻辑在 `computeView` / `SessionManagerPage` |
|
|
42
|
+
| `test/` | title / store-jsonl / state / service / api,共 26 个 |
|
|
43
|
+
|
|
44
|
+
### 0.1.1 列表逻辑(不要改坏)
|
|
45
|
+
|
|
46
|
+
- `computeView`:过滤 → 排序 → 分组 → 折叠 → 每组分页 → `visibleRows`;纯函数。
|
|
47
|
+
- 默认 `>100` 折叠;每工作区 50 条;`loadMore` 只改 `limits`,不改可见集。
|
|
48
|
+
- `viewKey` 变化(tab/工作区/搜索/展开集合/刷新)后 `selected = selected ∩ visibleIdSet`。
|
|
49
|
+
- 行 checkbox 的 `onSelect` 与工作区头 `onToggle` 必须分开;曾因此误折叠工作区。
|
|
50
|
+
- sticky 使用 `--dsw-alias-bg-layer-2`(与设置面板一致),不要改回 `bg-base` 黑色。
|
|
51
|
+
|
|
52
|
+
## 3. 下一步任务
|
|
53
|
+
|
|
54
|
+
### P0 — 等市场 gate / 合并(无代码)
|
|
55
|
+
|
|
56
|
+
1. 满 1 天后重新查看 `gh pr checks 9672 --repo awesome-dsh-plugin/awesome-dsh-plugin`。
|
|
57
|
+
2. gate 转绿后不要重复提交;等待维护者合并。
|
|
58
|
+
3. 合并后验证市场目录:`plugins.json` / dshmarket 搜索 / 卡片版本 `0.1.1` / 4 张截图 / `icon-180.png`。
|
|
59
|
+
4. 把结果回填到 `docs/02-open-source-and-marketplace.md` 第 7 节和 `docs/RELEASE-CHECKLIST-0.1.1.md` 的 E 节。
|
|
60
|
+
5. 如果维护者要求改描述/分类,只改 PR 里的那 1 个 YAML;代码仓库的发版不受影响。
|
|
61
|
+
|
|
62
|
+
### P1 — 0.2.0:Host 侧 overview + 分页 sessions(主任务)
|
|
63
|
+
|
|
64
|
+
目标:真正支撑 **1000–10000 条会话**,不再首屏拉全量 state。0.1.1 只是客户端折叠/分页,state payload 仍是全量(202 条约 103 KB;10000 条约 5 MB)。
|
|
65
|
+
|
|
66
|
+
建议(实现前先写 `docs/PLAN-2026-10-28.md` 并让子龙批准):
|
|
67
|
+
|
|
68
|
+
1. **`GET /session-mng/api/overview`**
|
|
69
|
+
- 只返回 `workspaces[]`(id/title/path/status/sessionIds.length/archivedCount/总大小)+ `totals` + `capabilities` + `orphans`。
|
|
70
|
+
- 计数优先用 `workspaceRegistry` 的内存 `sessionIds` / archived set;不要为计数读全部标题或日志。
|
|
71
|
+
- 未分组会话数量:需要一次 header 扫描;做成懒加载 + 短 TTL 缓存,不阻塞首屏。
|
|
72
|
+
2. **`GET /session-mng/api/sessions?workspaceId=&tab=&offset=&limit=&query=&sort=`**
|
|
73
|
+
- 只对当前页 id 做 `readTitleSnapshots` / `stat`;返回 `rows/total/offset/limit/hasMore`。
|
|
74
|
+
- 已归档:用 `archivedSessionIds` 过滤 workspace 账本;不要扫全量日志。
|
|
75
|
+
- 排序必须在 host 完成,保证分页稳定。
|
|
76
|
+
3. **全局搜索**
|
|
77
|
+
- 先只读验证 `sessionController.search` / `sessionQuery.searchSessions` 是否覆盖标题;不覆盖就限制为“当前工作区/已加载页标题搜索”,内容搜索走宿主索引。
|
|
78
|
+
- 搜索结果返回 id 列表后再按页补标题/大小,避免全量读标题。
|
|
79
|
+
4. **Client**
|
|
80
|
+
- `overview` 首屏 → 默认折叠;展开工作区时请求第一页;`加载更多` 请求下一页;缓存每工作区页。
|
|
81
|
+
- 保持 0.1.1 的 sticky、选择裁剪、搜索自动展开、视觉规范。
|
|
82
|
+
- 选择语义:优先保留“可见集”语义;跨页选择需要明确“已加载页”边界,避免隐藏页误操作。
|
|
83
|
+
5. **兼容**
|
|
84
|
+
- 保留 `GET /state` 给 0.1.x 客户端;Host 同时提供新旧接口,客户端 feature-detect.
|
|
85
|
+
- 版本 0.2.0;升级 README/CHANGELOG/ROADMAP;新增 `docs/RELEASE-CHECKLIST-0.2.0.md`.
|
|
86
|
+
6. **验收**
|
|
87
|
+
- 合成 10k 会话数据:首屏 overview 不带 session rows;单页 ≤50 行;不触发全量 `sessionController.list`。
|
|
88
|
+
- 现有 26 个测试 + 新增 overview/page/search/分页/空态/归档/未分组测试。
|
|
89
|
+
- 实机只读验证 202 条真实数据,再用手动合成数据验证 1000/10000;写操作仍只用一次性测试会话。
|
|
90
|
+
|
|
91
|
+
### P2 — 后续候选(不急)
|
|
92
|
+
|
|
93
|
+
侧栏会话菜单、全文搜索、导出、置顶、整枝移动、会话体检/修复、回收站、增量移动。按 `ROADMAP.md` 逐项排,不要一次全做。
|
|
94
|
+
|
|
95
|
+
## 4. 发布 / 开发命令
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
cd /Users/zilong/zWork/ai/zl-plugins/dsh-session-mng
|
|
99
|
+
|
|
100
|
+
npm test
|
|
101
|
+
node --check index.js client.js lib/*.js
|
|
102
|
+
npm --cache /tmp/dsh-npm-cache pack --dry-run
|
|
103
|
+
|
|
104
|
+
# npm 发布(0.1.x 均出现 202 + 0.0.0-stage 占位,约 90s 后 packument 出现新版本;以版本端点为准)
|
|
105
|
+
npm --cache /tmp/dsh-npm-cache publish
|
|
106
|
+
curl -s -o /dev/null -w "%{http_code}\n" https://registry.npmjs.org/dsh-session-mng/<version>
|
|
107
|
+
|
|
108
|
+
# GitHub
|
|
109
|
+
git push origin main
|
|
110
|
+
git tag v<version> && git push origin v<version>
|
|
111
|
+
gh release create v<version> --repo ZilongYang/dsh-session-mng --title "dsh-session-mng <version>" --notes-file /tmp/notes.md
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## 5. 环境与坑
|
|
115
|
+
|
|
116
|
+
- DSH `0.2.1-rc.2`;Desktop `desktop` profile **由应用独占**,不要用 `dsh plugin --profile desktop …` 管理;用应用内插件管理器或 `plugin_manager`。
|
|
117
|
+
- Client 服务只能 `ctx.get('uiWorkspace')`;直接 `ctx.uiWorkspace` 在未 inject 时会抛错,且被 try/catch 吞掉会导致“恢复并打开”消失。
|
|
118
|
+
- 移动依赖 workspace registry 内部缓存 seam;已做特性检测和回滚,升级 DSH 先跑测试 + 实机验收。
|
|
119
|
+
- 移动/删除只支持本地 JSONL;live 会话拒绝移动/删除,重启后重试。
|
|
120
|
+
- 测试/截图只用一次性测试会话或 `/Users/demo/...` + `session-demo-*` 假数据;不要提交真实标题/路径/会话 id。
|
|
121
|
+
- 公开计划是脱敏版;逐字原文在 `private/raw-plans/`(gitignore,不进 npm)。
|
|
122
|
+
- 0.1.1 的 npm tarball 是在最终文档回填前打的,包内 checklist 可能显示 pending;功能/README 无影响。不值得为这个单独发 0.1.2。
|
|
123
|
+
- GitHub tag `v0.1.1` 指向 `1b6a07f`;之后只有文档提交 `7e1b457`,代码一致。
|
|
124
|
+
|
|
125
|
+
## 6. 关键文档
|
|
126
|
+
|
|
127
|
+
- [0.1.0 批准计划](PLAN-2026-10-26.md)
|
|
128
|
+
- [0.1.1 实施计划](PLAN-2026-10-27.md)
|
|
129
|
+
- [0.1.1 发布清单](RELEASE-CHECKLIST-0.1.1.md)
|
|
130
|
+
- [设计说明](01-design.md)
|
|
131
|
+
- [开源/市场记录](02-open-source-and-marketplace.md)
|
|
132
|
+
- [路线图](../ROADMAP.md)
|
|
133
|
+
- [变更记录](../CHANGELOG.md)
|
package/docs/PLAN-2026-10-27.md
CHANGED
|
@@ -67,3 +67,5 @@
|
|
|
67
67
|
5. **新增第 4 张截图** `screenshot-4-expanded.png`,展示工作区展开、选择 2 条活跃会话、sticky 过滤 + 批量条;市场可展示 4 张。
|
|
68
68
|
6. **实现中修了一个行选择事件绑定 bug**:Group 的行 checkbox 最初误调用工作区折叠函数(`toggleGroup`),已拆成 `onSelect` / `onToggle` 两个 prop;该 bug 只存在于工作区,未进入 0.1.0 发布。
|
|
69
69
|
7. **0.1.1 仍是客户端快修**:首屏继续拉全量 state(202 条约 103 KB;10000 条约 5 MB),真正按工作区懒加载/分页在 0.2.0 做。这一点在验收时明确,不把 0.1.1 当成 10000 条的解决方案。
|
|
70
|
+
|
|
71
|
+
8. **发布结果(2026-10-27)**:0.1.1 已发布;npm `latest` = 0.1.1(31 文件,560.7 kB),GitHub main / tag `v0.1.1` / Release 已更新;marketplace 条目不变,版本随 npm 自动更新。
|
|
@@ -35,8 +35,21 @@
|
|
|
35
35
|
|
|
36
36
|
## D. 发布
|
|
37
37
|
|
|
38
|
-
- [x] `npm --cache /tmp/dsh-npm-cache pack --dry-run`:31 个文件 / 560.8 kB / unpacked
|
|
39
|
-
- [
|
|
40
|
-
- [
|
|
41
|
-
- [
|
|
42
|
-
- [
|
|
38
|
+
- [x] `npm --cache /tmp/dsh-npm-cache pack --dry-run`:31 个文件 / 560.8 kB;npm 发布实际 tarball 560.7 kB / unpacked 767.4 kB;包含 4 张截图。
|
|
39
|
+
- [x] `npm publish` 0.1.1(`+ dsh-session-mng@0.1.1`);版本端点 HTTP 200,`latest` = 0.1.1,`dist.fileCount` = 31。发布后约 90 秒 packument 才出现 0.1.1(与 0.1.0 相同的 staged 处理)。
|
|
40
|
+
- [x] Git commit `cea99f9` + push main + tag `v0.1.1` + GitHub Release(https://github.com/ZilongYang/dsh-session-mng/releases/tag/v0.1.1)。
|
|
41
|
+
- [x] 确认 npm `latest` = 0.1.1;marketplace 条目无需改 YAML,市场卡片版本随 npm 自动更新。
|
|
42
|
+
- [x] 在 `docs/02-open-source-and-marketplace.md` 记录 0.1.1 发布结果。
|
|
43
|
+
|
|
44
|
+
## E. 市场收录(进行中)
|
|
45
|
+
|
|
46
|
+
- [x] PR [#9672](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin/pull/9672) 已提交,只新增 1 个 YAML;条目不需要随 0.1.1 改。
|
|
47
|
+
- [x] `check` 已通过。
|
|
48
|
+
- [ ] `Submission gate`:当前仅因仓库 0.0 天(需要 1 天)失败;约 2026-10-28 00:44 Asia/Shanghai 自动重跑,不要重新提交/关闭重开。
|
|
49
|
+
- [ ] gate 转绿后等待维护者合并。
|
|
50
|
+
- [ ] 合并后验证 `plugins.json` / dshmarket 搜索、卡片版本 `0.1.1`、4 张截图、icon。
|
|
51
|
+
- [ ] 结果回填 `docs/02-open-source-and-marketplace.md` 与本节。
|
|
52
|
+
|
|
53
|
+
## F. 接手
|
|
54
|
+
|
|
55
|
+
完整接手说明、0.2.0 任务、环境坑见 [HANDOVER-2026-10-27.md](HANDOVER-2026-10-27.md)。
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# dsh-session-mng 0.1.2 发布检查清单
|
|
2
|
+
|
|
3
|
+
> 记录时间:2026-10-27。0.1.2 是空会话清理 + 删除范围弹窗的客户端修复;Host API 未变。**当前未发布**,等子龙实机测试后再执行 npm/GitHub。
|
|
4
|
+
|
|
5
|
+
## A. 实现
|
|
6
|
+
|
|
7
|
+
- [x] 默认隐藏 `blank: true` 的空会话;新增「显示空会话」开关。
|
|
8
|
+
- [x] 全部/活跃/已归档 tab 计数与隐藏空会话后的可见列表一致。
|
|
9
|
+
- [x] 总览行显示「已隐藏 N 个空会话」;显示空会话时才显示“未归档空会话需先归档”提示。
|
|
10
|
+
- [x] 头部新增「清理空会话(N)」:只收集 `blank && archived && can.delete` 的会话,打开删除范围预览;未归档空会话不混入。
|
|
11
|
+
- [x] 删除范围确认改为模态:内容区独立滚动、底部勾选/确认/取消固定;支持遮罩点击与 Esc 取消。
|
|
12
|
+
- [x] 单条详情里的删除范围与批量删除共用同一模态。
|
|
13
|
+
|
|
14
|
+
## B. 验证
|
|
15
|
+
|
|
16
|
+
- [x] `node --check client.js`。
|
|
17
|
+
- [x] `node --test` 26 个测试全绿(Host/标题/移动/删除未改)。
|
|
18
|
+
- [x] React render smoke(4 条假会话、2 条空白归档):
|
|
19
|
+
- 默认只渲染 2 条非空会话;tab 全部/活跃/已归档 = 2/2/0;`清理空会话` 按钮存在。
|
|
20
|
+
- 打开清理 → `.dsm-scope-overlay` / `.dsm-scope-dialog` / `.dsm-scope-foot` 存在;确认按钮 disabled;取消后弹窗消失。
|
|
21
|
+
- 勾选「显示空会话」→ 行数 4;再取消。
|
|
22
|
+
- [ ] 子龙实机测试:默认隐藏、显示空会话、清理空会话(**不要确认删除真实空会话**,除非明确要清)、删除范围弹窗滚动时底部按钮可见。
|
|
23
|
+
- [ ] 若确认文案/按钮位置需要微调,再改一轮。
|
|
24
|
+
|
|
25
|
+
## C. 发布(待批准)
|
|
26
|
+
|
|
27
|
+
- [x] `npm pack --dry-run`:33 个文件 / 568.2 kB(比 0.1.1 多 2 个 docs)。
|
|
28
|
+
- [ ] `npm publish` 0.1.2;验证版本端点与 latest。
|
|
29
|
+
- [ ] Git commit / push / tag `v0.1.2` / GitHub Release。
|
|
30
|
+
- [ ] 市场条目不需要改 YAML;版本随 npm 自动更新。
|
|
31
|
+
- [ ] 更新 `CHANGELOG` 的 unreleased 标记、README 当前状态、ROADMAP、`docs/HANDOVER-2026-10-27.md`。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-session-mng",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Session management for DeepSeek Harness: one Settings page for every session — whole-session title generation, archive/restore, cross-workspace move, and permanent deletion of archived sessions.",
|
|
6
6
|
"license": "MIT",
|