Skip to content
dsh.fish
Bundle

dsh-session-title-cold

冷会话标题回填:把持久化日志里的 session/title 事件折叠进 projection 缓存,让 session.list 的 projections 带上真实标题——侧边栏会话列表不再全部显示工作区目录名(dsh)。

Source
fengs2021
License
MIT
Updated
Updated 3 days ago

Readme

# dsh-session-title-cold

> Cold-session title backfill for DeepSeek Harness: rows in `session.list` that come from persisted cold sessions (never opened, especially subagent children) have no projection cache, so the sidebar falls back to the workspace directory name — a screen full of "dsh" with no way to tell sessions apart. This plugin scans persisted sessions in the background, folds each registered projection unit (title / sessionStats / sessionListMetadata …) down to the latest event, and writes the title back into the projection cache.
>
> DSH 冷会话标题回填:后台扫描持久化会话,把投影单元折叠到最新事件并写回缓存,会话列表显示真实标题而不是工作区目录名。

---

## English

### Problem

`session.list` rows backed by persisted *cold* sessions (never opened, especially subagent children) have no projection cache, so the sidebar falls back to the workspace directory name (e.g. `dsh`) — you cannot tell sessions apart.

### What it does

On startup (and then incrementally), scans all persisted sessions, folds each registered projection unit (`title` / `sessionStats` / `sessionListMetadata` …) down to the latest event, and writes the title back into the projection cache. Afterwards every `session.list` row carries `projections.values.title`, and the frontend shows the real title (fallback: first message, or the LLM/user rename).

### Features

- **Zero intrusion**: no dsh source changes; a pure server-side plugin using the official projection registration/cache extension points
- **Incremental**: sessions that already have cache rows only read the event tail (`restoreFloor → readFrom`), refreshed every 10 minutes; new renames are absorbed automatically
- **Fail-soft**: a single session failure logs at debug level and never blocks the batch; live sessions are skipped (their cache is maintained by the runtime persistence path, avoiding overwriting fresh state)

### Install

- Plugin directory: `~/.dsh/plugins/dsh-session-title-cold/`
- Profile registration (`cordis.patch.yml`):

```yaml
- insert:
    - id: session-title-cold
      name: dsh-session-title-cold
```

Restart `dsh web` — backfill starts 5 seconds after boot (log `[title-cold] 回填完成:N 个会话`), refresh the web sidebar to see real titles.

### Config (optional)

```yaml
- id: session-title-cold
  name: dsh-session-title-cold
  config:
    backfillDelayMs: 5000     # delay before backfill after boot
    refreshIntervalMs: 600000 # incremental refresh period
    concurrency: 3            # concurrent disk reads
```

### How it works

1. `sessionProjections.restoreFloor(checkpoint)` → incremental read floor
2. `sessionPersistence.readFrom(id, floor)` → read the tail events (with seq)
3. `sessionProjections.restore(checkpoint, events, floor)` → fold all unit snapshots (including `title` from `session/title` events: fallback / user rename)
4. Merge **only the `title` row** into the cache and write back via `sessionProjectionCache.putSoft` (other units of a cold session may hold non-pure-JSON state — skipped to avoid `not losslessly JSON-serializable` rejections of the whole row)
5. The next `session.list` carries `projections.values.title`; `displayTitleOf` no longer falls back to the directory name

## 中文

### 问题

`session.list` 的行若来自持久化冷会话(从未打开过、尤其 subagent 子会话),projection 缓存里没有它们的行,列表拿不到标题,侧边栏只能 fallback 显示工作区目录名(如 `dsh`),一屏全是 "dsh" 分不清谁是谁。

### 功能

启动后后台扫描全部持久化会话,把每个已注册 projection unit(title / sessionStats / sessionListMetadata 等)折叠到最新事件并写回 projection 缓存;之后 `session.list` 每行都带 `projections.values.title`,前端列表直接显示真实标题(fallback 自首条消息,或 LLM/用户重命名)。

### 特性

- **零侵入**:不改 dsh 源码,纯服务端插件,利用官方 projection 注册/缓存扩展点
- **增量**:已有缓存行的会话只读事件尾部(restoreFloor → readFrom),每 10 分钟刷新一次,rename 等新标题变化自动吸收
- **fail-soft**:单个会话失败只记 debug 日志,不阻断批次;live 会话自动跳过(它们的缓存由运行时落盘路径维护,避免覆盖新状态)

### 安装

- 插件目录:`~/.dsh/plugins/dsh-session-title-cold/`
- profile 注册(cordis.patch.yml):

```yaml
- insert:
    - id: session-title-cold
      name: dsh-session-title-cold
```

重启 dsh-web 后,启动 5 秒后台回填(日志 `[title-cold] 回填完成:N 个会话`),刷新网页侧边栏即可看到全部真实标题。

### 配置(可选)

```yaml
- id: session-title-cold
  name: dsh-session-title-cold
  config:
    backfillDelayMs: 5000     # 启动后多久开始回填
    refreshIntervalMs: 600000 # 增量刷新周期
    concurrency: 3            # 并发读盘数
```

### 工作原理

1. `sessionProjections.restoreFloor(checkpoint)` 得出增量读起点
2. `sessionPersistence.readFrom(id, floor)` 读尾部事件(带 seq)
3. `sessionProjections.restore(checkpoint, events, floor)` 折叠出全部 unit 快照(含 `title`,来自 `session/title` 事件,如 fallback/用户重命名)
4. 只把 `title` 行合并进缓存并 `sessionProjectionCache.putSoft` 写回(cold 会话其余 unit 的 state 可能含非纯 JSON 值,跳过不写,避免 `not losslessly JSON-serializable` 拒绝整行)
5. 前端下一次 `session.list` 即带 `projections.values.title`,`displayTitleOf` 不再 fallback 到目录名

## License

MIT

Install

dsh plugin --profile web add github:fengs2021/dsh-session-title-cold#e844ca7bfd886f5a569150c6766759fddbd57c07

Profile: web

Source