dsh-quick-toc 0.4.0 → 0.5.0

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.en.md CHANGED
@@ -2,31 +2,55 @@
2
2
 
3
3
  All notable changes to **dsh-quick-toc** are documented here. Chinese version: [CHANGELOG.md](CHANGELOG.md).
4
4
 
5
+ ## [0.5.0] - 2026-09-12
6
+
7
+ ### Added
8
+ - **Whole-session turn index**: with the host's `turnOutline` projection the outline now covers **every turn of the session**, including turns the paged event window has not loaded. Unloaded turns appear as entries tagged 未加载 with the host's prompt/response previews (host-side budgets: 50 / 120 characters); clicking one pages that turn in through the host's turn-jump loader and scrolls to it. On a host without the projection the panel degrades to loaded turns only.
9
+ - **Row subtitles**: under each heading the panel shows the first sentence of that section's body (skipping blank lines, fenced code, table rules and bare bullet markers), so identically-titled headings can be told apart at a glance.
10
+ - **Hover previews**: hovering a heading or result row opens a card after ~0.26s with the title, turn time, heading path and the section's opening (up to 260 characters); docked right, the card opens to the left; leaving the row fades it out.
11
+ - **Search normalization (always on)**: letter case, full-width/half-width forms and runs of whitespace count as the same match, and the highlight lands on the real characters of the original text.
12
+ - **"Fuzzy" switch**: an independent toggle next to the title/full-text pill. When on, a query also matches text with a little material wedged in between (subsequence matching with a bounded gap); the setting is remembered.
13
+ - **Unloaded turns are searchable too**: full-text scope also searches the previews of unloaded turns, and clicking such a hit loads the turn first, then locates and highlights.
14
+ - **Edge hints**: under the search results, "scroll up to load earlier messages" — dismissed by the first upward scroll. In the outline, reaching the first turn (or scrolling down while already at the last) flashes "已经是最早的消息" / "已经到底了" at the bottom of the panel: fade in, ~2.6s hold, fade out.
15
+
16
+ ### Changed
17
+ - **Auto-follow tracks more tightly**: the artificial delay is gone, the outline positions itself instantly instead of animating after the conversation, and the highlight transition dropped from 0.3s to 0.15s. Following no longer depends on the one scroll container captured at mount — it listens on the document in the capture phase and re-queries the container on every run, with a slow poll as a backstop, so it also keeps working after programmatic jumps (the native turn rail).
18
+ - **The turn being read is marked by a closed blue box** (light fill + outline + left accent bar) that fades in and out; other turns are no longer dimmed into grey (0.6 → 0.85) and the panel's idle opacity went 0.45 → 0.72, which makes the whole list far more readable.
19
+ - **Heading-less turns** promote their time row to body-level size and weight (12px / 600 / primary colour) instead of a grey caption, and they now look the same as headed turns when they are the one being read.
20
+ - Active-state colour collapsed onto a single source: the search button, the level-filter button (including while it animates shut), the title/full-text pill, the fuzzy switch, the level chips and the current result row all use the same tint.
21
+ - The click on the host's "load earlier" is throttled to 900ms while scrolling the outline (one continuous scroll cannot hammer the pager); scrolling the outline still both expands the index and loads older conversation, as in 0.4.x.
22
+ - Every UI string now comes from one table, preparing the zh/en split (the 0.5.0 interface is still Chinese).
23
+
24
+ ### Fixed
25
+ - After jumping with the native turn rail (the tick bar on the right of the conversation), the outline stopped following and no longer lit up the turn being read: the follow listener was bound to the scroll container captured **at mount**, and a jump that repages the window replaces that container, so the listener sat on a discarded node and never saw another scroll event. It now listens on the document in the capture phase and re-queries the current container on every run.
26
+ - A turn without Markdown headings could never become the turn being read (no highlight, no follow): the node→turn map used by the follow only registered messages that carry headings. Every node of the turn (the user message and each model reply) is registered now.
27
+
5
28
  ## [0.4.0] - 2026-09-11
6
29
 
7
30
  ### Added
31
+ - **Search result list**: while a query is present the outline becomes a result list — one row per match, showing the matched heading or message with the keyword highlighted, its heading path, the turn time and a repeat count (plus a context snippet in full-text scope). Rows are chronological with the **newest hit at the bottom**, a fresh search starts at the newest hit and you scroll up to reach earlier ones; **clicking a row** makes that hit current, i.e. the same path as Enter stepping — it highlights the keyword in the conversation and scrolls there. `n/N` Enter-stepping is kept.
8
32
  - **Sticky group headers**: while scrolling the outline, the header of the turn you are inside stays pinned to the top of the panel, flush against the toolbar above it.
9
33
  - **Collapsible level-filter row**: the **层级 (levels)** button at the left of the magnifier hides/shows the `1`–`6` row (the choice is remembered; the filter keeps applying while it is hidden).
10
34
  - **Position breadcrumb**: the top of the panel shows the path of the section you are reading; click it to jump there. The rule is "the deepest heading above the viewport's middle line" — the section that fills most of the screen — and since a jump also lands above that line, the breadcrumb still shows the same heading after you click it.
11
35
  - **Heading level filter**: the `1`–`6` chips at the top of the panel are independent switches, so any combination works (e.g. H1 and H3 with H2 hidden) and the choice is remembered; switching off the last remaining level restores all six.
12
- - **Search result list**: while a query is present the outline becomes a result list — one row per match, showing the matched heading or message with the keyword highlighted, its heading path, the turn time and a repeat count (plus a context snippet in full-text scope). Rows are chronological with the **newest hit at the bottom**, a fresh search starts at the newest hit and you scroll up to reach earlier ones; **clicking a row** makes that hit current, i.e. the same path as Enter stepping — it highlights the keyword in the conversation and scrolls there. `n/N` Enter-stepping is kept.
13
36
 
14
37
  ### Changed
15
- - **Compatibility**: verified against and declared for DSH **0.1.5-rc.1 and 0.1.5-rc.2** (`engines.dsh` keeps its floor of `>=0.1.5-rc.1`). The host interface is identical in both — the session-scoped slot `conversation.input.overlay`, the `useChat` hook from `dsh-client-ui-chat` and the client-module seed table were all checked against the installed bundles.
16
38
  - **Performance**: heading parsing and text extraction are now cached per node, so a streaming update only re-processes the node that changed instead of the whole history; the cache drops nodes that left the conversation, keeping it bounded.
39
+ - The turn header (the time row) now jumps to the **start of that turn's model reply** (it used to jump to the user message).
40
+ - **Compatibility**: verified against and declared for DSH **0.1.5-rc.1 and 0.1.5-rc.2** (`engines.dsh` keeps its floor of `>=0.1.5-rc.1`). The host interface is identical in both — the session-scoped slot `conversation.input.overlay`, the `useChat` hook from `dsh-client-ui-chat` and the client-module seed table were all checked against the installed bundles.
17
41
  - `countOccurrences` now guards an empty needle (an empty query made `indexOf` spin in place — an infinite loop; every current call site is guarded, so this is hardening).
18
42
 
19
43
  ### Fixed
20
44
  - The outline did not jump to the newest turn when content first appeared: that effect's dependency array was written above the `groups` declaration, so it always evaluated to `0` during render and the effect only ever ran on mount. The effect now sits below `groups` and depends on `groups.length`.
21
- - Result rows always reported a repeat count of 1 (the `×N` badge never appeared), which also made the "row holding the current match" highlight land on the next row when one heading matched twice. Each row now records its real occurrence count.
22
45
  - Dragging the top bar to move the panel persisted the position from **before** the drag (the closure kept the value captured at pointer-down), so the panel jumped back to its old spot after a reload. It now stores the position the drag ended at.
23
- - In full-text scope, clicking a row whose hit was in a message body only scrolled and never highlighted anything (the click used the jump-only path while highlighting only happened while Enter-stepping). Clicking a result row now shares the stepping path: highlight that hit, scroll to it, and update both `n/N` and the highlighted row.
24
46
  - When the same keyword occurred more than once inside one text node, the in-chat highlight wrapped only the FIRST occurrence there, so the later one was neither tinted nor eligible to be marked as the current hit — stepping to it found no current mark and degraded to a plain scroll with no distinct highlight. Every occurrence inside each text node is now wrapped in order, so the in-conversation hit order lines up with `n/N`.
25
- - Breadcrumb and jump were inconsistent: detection used "the last heading above the viewport top" while a jump puts the heading 20 px below the top, so clicking the breadcrumb switched it to the previous heading. Both now use the viewport's **middle line**, which both reflects the section filling most of the screen and stays consistent with every jump target.
26
- - The level filter used to be a "show up to level N" prefix that could not skip an intermediate level; it is now a per-level switch.
27
- - The turn header (the time row) jumped to the turn's **user message**; it now jumps to the **start of that turn's model reply**, and turns without any headings — which have only this row in the panel — are clickable too.
28
47
  - `# comment` / `## example` lines inside a ``` fenced code block were treated as headings and leaked into the outline: they have no element to jump to, and they shifted the index of the real headings after them so those jumped to the wrong place. Heading parsing now skips fenced blocks (``` and ~~~, info strings, longer closing fences, up to 3 spaces of indentation).
29
- - There was a gap between the pinned group header and the toolbar above it: the scroll container's 6 px top padding is a wall a sticky row cannot pass. The top padding is gone, so the header butts against the toolbar; spacing between groups comes from the divider.
48
+
49
+ ## [0.4.1] - 2026-09-12
50
+
51
+ ### Changed
52
+ - **Heading levels are now a popup**: a round icon button in the header (three lines of decreasing width, hover feedback matching the magnifier) scales the H1–H6 picker out of the **button's center**, right-aligned with an outer shadow; closing shrinks it back into the button with a fade. The picker no longer occupies its own row, the chips are labelled H1–H6, and their selected tint matches the title / full-text toggle.
53
+ - Removed the "you are here" breadcrumb row introduced in 0.4.0 (it felt unnecessary in use).
30
54
 
31
55
  ## [0.3.3] - 2026-09-10
32
56
 
package/CHANGELOG.md CHANGED
@@ -2,31 +2,55 @@
2
2
 
3
3
  **dsh-quick-toc** 的重要变更都记录在这里。英文版见 [CHANGELOG.en.md](CHANGELOG.en.md)。
4
4
 
5
+ ## [0.5.0] - 2026-09-12
6
+
7
+ ### 新增
8
+ - **全量回合索引**:接入宿主的 `turnOutline` 投影后,大纲覆盖**整段会话**的回合,包括分页窗口尚未加载进来的那些。未加载的回合显示为带「未加载」标记的条目,附宿主提供的提问/回答预览(宿主侧上限 50 / 120 字),点击即通过宿主的回合跳转加载器把该回合翻页加载进来再滚过去。宿主没有该投影时退化为只列已加载的回合。
9
+ - **标题行副标题**:每个标题下方显示该节正文的第一句(跳过空行、围栏代码块、表格线与纯项目符号),同名标题一眼可辨。
10
+ - **悬停预览**:悬停标题行或结果行约 0.26 秒后弹出预览卡片,显示标题、回合时间、层级路径与该节开头(最多 260 字);面板停靠右侧时卡片弹在左侧;移开鼠标渐隐。
11
+ - **搜索归一化(常开)**:大小写、全角/半角、连续空白差异视为同一个匹配,命中高亮落在原文的真实字符上。
12
+ - **「模糊」开关**:搜索框右侧、与「标题/全文」并排的独立开关。开启后允许关键字中间夹少量其他文字(子序列匹配,跨度有上限),开关状态会被记住。
13
+ - **未加载的回合也能被搜到**:「全文」范围同时搜索未加载回合的预览文本,命中行的点击同样是"先加载、再定位并高亮"。
14
+ - **边界提示**:搜索结果下方提示「向上滚动可加载更早的消息」,往上一滚即消失;大纲态滚到第一条、或已在最后一条仍继续下滚时,面板底部浮出「已经是最早的消息」/「已经到底了」,渐显、停留约 2.6 秒后渐隐。
15
+
16
+ ### 变更
17
+ - **自动跟随更跟手**:去掉跟随路径上的人为延时、大纲改为瞬时定位(不再用平滑动画追赶)、高亮过渡由 0.3 秒缩到 0.15 秒。跟随也不再依赖"挂载时抓到的那一个滚动容器"——改为在 document 捕获阶段监听并在每次运行时重新查询容器,另加低频轮询兜底,程序化跳转(原生回合轨道)之后也能继续跟随。
18
+ - **正在阅读的回合改用封闭的蓝色框**标记(浅蓝填充 + 四周描边 + 左侧强调条),出现与消失都是渐显渐隐;其余回合不再压到很暗(0.6 → 0.85),面板静止透明度 0.45 → 0.72,整体可读性提升。
19
+ - **无标题回合的时间行**提升为正文级字号与字重(12px / 600 / 正文色),不再是一行灰色小注;有标题与无标题的回合在成为"正在阅读"时外观一致。
20
+ - 界面激活态配色收敛到单一色源:搜索按钮、层级筛选按钮(含收回动画期间)、「标题/全文」、「模糊」开关、层级芯片、搜索结果当前行统一使用同一个浅蓝。
21
+ - 往上翻大纲时对宿主的「加载更早」点击加了 900ms 节流(连续滚动不会反复触发分页);大纲态"滚动既展开索引、也加载更早的对话"这一行为与 0.4.x 保持一致。
22
+ - 所有界面文案收敛到一张字符串表,为后续中英双语做准备(0.5.0 的界面文字仍是中文)。
23
+
24
+ ### 修复
25
+ - 用对话右侧的原生回合轨道(刻度条)跳转之后,大纲不再自动跟随、正在阅读的回合也不再点亮:跟随的滚动监听绑在**挂载时抓到的那个滚动容器**上,而跳转重新分页时该容器会被替换,监听器留在被丢弃的节点上,从此收不到任何滚动事件。现在改为在 document 捕获阶段监听,并在每次运行时重新查询当前容器。
26
+ - 没有 Markdown 标题的回合无法成为"正在阅读"的回合(不点亮、不跟随):跟随用的"节点 → 回合"映射只登记了带标题的消息,无标题回合的节点一个都没登记。现在该回合的所有节点(用户消息与每条模型回复)都会登记。
27
+
5
28
  ## [0.4.0] - 2026-09-11
6
29
 
7
30
  ### 新增
31
+ - **搜索结果列表**:有搜索词时大纲切换为结果列表,逐条列出命中(标题关键字高亮、层级路径、回合时间、重复次数,全文模式附上下文片段)。列表按时间排列、**最新的命中在底部**,开始搜索时自动定位到最新命中,向上滚回看更早的命中;点击任一行会把该命中设为当前命中——和回车逐处跳同一条路径,会在对话里高亮并滚过去;`n/N` 回车逐处跳保留
8
32
  - **组头吸顶**:滚动大纲时,当前所在回合的组头固定在面板顶部,并与上方工具条紧贴
9
33
  - **层级筛选行可收起**:标题栏放大镜左边的 **层级** 按钮收起/展开 `1`–`6` 那一行(选择会记住;收起后筛选设置仍然生效)
10
34
  - **位置面包屑**:面板顶部显示你正在读的章节路径,点击可跳到该标题。判定规则是"视口中线之上最深的标题"(画面里占得最多的那一节);跳转落点也在中线之上,所以点完后面包屑显示的仍是同一个标题
11
35
  - **标题层级筛选**:面板顶部 `1`–`6` 芯片是各自独立的开关,可任意组合(例如只留 H1 与 H3、关掉中间的 H2),选择会记住;把最后一个亮着的层级也关掉时自动恢复显示全部六级
12
- - **搜索结果列表**:有搜索词时大纲切换为结果列表,逐条列出命中(标题关键字高亮、层级路径、回合时间、重复次数,全文模式附上下文片段)。列表按时间排列、**最新的命中在底部**,开始搜索时自动定位到最新命中,向上滚回看更早的命中;点击任一行会把该命中设为当前命中——和回车逐处跳同一条路径,会在对话里高亮并滚过去;`n/N` 回车逐处跳保留
13
36
 
14
37
  ### 变更
15
- - **兼容性**:在 DSH **0.1.5-rc.1 与 0.1.5-rc.2** 上验证并声明兼容(`engines.dsh` 下限仍为 `>=0.1.5-rc.1`)。两版的宿主接口一致——会话级槽位 `conversation.input.overlay`、`dsh-client-ui-chat` 的 `useChat` hook 与客户端模块 seed 表都经实测核对相同。
16
38
  - **性能**:标题解析与文本提取改为按节点缓存——流式更新只重算真正变化的节点,不再每次重算整段历史;缓存会清理已离开会话的节点,保持有界
39
+ - 回合组头(时间那一行)点击改为跳到**该回合模型回答的开头**(原来跳到用户消息位置)
40
+ - **兼容性**:在 DSH **0.1.5-rc.1 与 0.1.5-rc.2** 上验证并声明兼容(`engines.dsh` 下限仍为 `>=0.1.5-rc.1`)。两版的宿主接口一致——会话级槽位 `conversation.input.overlay`、`dsh-client-ui-chat` 的 `useChat` hook 与客户端模块 seed 表都经实测核对相同。
17
41
  - `countOccurrences` 增加空查询守卫(空查询会让 `indexOf` 原地打转导致死循环;现有调用点都有守卫,此举为加固)
18
42
 
19
43
  ### 修复
20
44
  - 大纲首次载入内容时没有自动定位到最新回合:该副作用的依赖数组写在 `groups` 声明之前,渲染时读到的永远是 `0`,导致副作用只在挂载时执行一次。已把副作用移到 `groups` 之后并直接依赖 `groups.length`。
21
- - 搜索结果行的重复次数恒为 1(`×N` 从不显示),并连带使"当前命中所属行"在重复命中时定位到下一行。现在每行记录真实的出现次数。
22
45
  - 拖动顶部横条调整面板垂直位置后,记录的仍是**拖动前**的位置(写入的是拖动开始时闭包里的旧值),刷新后面板跳回原位。现在写入拖动结束时的实际位置。
23
- - 全文搜索时,正文命中行点击后只滚动、不高亮(点击走的是"仅跳转"路径,而高亮只在回车逐处跳里做)。现在点击结果行与回车逐处跳共用同一条路径:先高亮该处,再滚过去,同时更新 `n/N` 与当前行高亮。
24
46
  - 同一段文本里同一关键字出现多次时,对话内高亮只包住**该文本节点里的第一处**:第二处既不染色,也无法被标成"当前命中",于是跳到第二处时找不到当前标记,退化成"只滚动、没有高亮"。现在每个文本节点内的所有出现都会依次包住,对话内命中序号与 `n/N` 完全对齐。
25
- - 面包屑与跳转错位:判定用"视口顶部之上最后一个标题",而跳转把标题放在"顶部 +20px",于是点完面包屑就会换成上一个标题。现在统一以**视口中线**为基准(既反映画面里占得最多的那一节,又与所有跳转落点自洽)。
26
- - 层级筛选原本是"显示到第 N 级"的前缀语义,无法跳过中间层级;现在改为逐级开关。
27
- - 回合组头(时间那一行)原本跳到该回合的**用户消息**位置;现在跳到**该回合模型回答的开头**,并且没有标题的回合(面板里只剩时间行)也能点。
28
47
  - ``` 围栏代码块里的 `# 注释` / `## 示例` 会被当成标题混进大纲(既没有可跳转的目标,又会让它后面那些真标题的序号错位、跳到错误位置)。现在解析标题时会跳过围栏代码块(支持 ``` 与 ~~~、带 info string 的开栏、更长的闭栏、最多 3 空格缩进)。
29
- - 吸顶的组头上边缘与上方工具条之间有一道空隙:滚动容器的上内边距(6px)把粘性行"顶"不下去。现在去掉该上内边距,组头紧贴工具条,组与组之间的间距由分隔线提供。
48
+
49
+ ## [0.4.1] - 2026-09-12
50
+
51
+ ### 变更
52
+ - **层级筛选改为弹出选择**:标题栏新增圆形图标按钮(三条递减横线,悬停反馈与放大镜一致),点击后从**按钮中心**放大弹出 H1–H6 选择层(靠右、带外阴影),收回时缩回按钮并渐隐,不再单独占一行;选择芯片标注 H1–H6,选中态配色与搜索的"标题 / 全文"切换一致
53
+ - 移除面板顶部的"当前位置"面包屑行(0.4.0 新增,使用中显得多余)
30
54
 
31
55
  ## [0.3.3] - 2026-09-10
32
56
 
package/README.en.md CHANGED
@@ -2,36 +2,39 @@
2
2
 
3
3
  > **English** | [中文](README.md)
4
4
 
5
- A conversation TOC plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH): it turns the Markdown headings (H1–H6) of AI replies into a navigable outline panel, grouped by conversation turn, with auto-follow highlighting, keyword search and in-chat match highlighting.
5
+ A conversation TOC plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH): it turns the Markdown headings (H1–H6) of AI replies into a navigable outline panel, grouped by conversation turn and covering the whole session (including turns that are not loaded yet), with title/full-text search, hover previews and reading-position auto-follow.
6
6
 
7
7
  ## Features
8
8
 
9
- - **Turn-grouped outline** — each user message plus its following AI replies form one group; the group header shows the turn's end time and a first-line preview, and clicking it jumps to the **start of that turn's model reply** (a turn with no headings has only this row and is still clickable)
10
- - **Keyword search** — the magnifier in the panel header opens a search box; press **Enter** to jump to the next match (wrapping), **Esc** to close, with an `n/N` match counter
11
- - **Search result list** — once a query is present the outline becomes a result list: each row is a matched heading or message (keyword highlighted) showing its heading path, the turn time and a repeat count, plus a context snippet in full-text scope. Rows run in chronological order (**newest hit at the bottom**) and a fresh search starts at the newest hit — scroll up to walk back through earlier ones; **clicking a row** makes that hit the current one, i.e. exactly what Enter stepping does: it highlights the keyword in the conversation and scrolls there
12
- - **Search scope toggle** — the **title / full-text** button in the search box switches between searching heading titles only and also searching user messages plus AI reply text
13
- - **In-chat highlighting** — matched keywords are highlighted in the conversation; the current match is highlighted distinctly and scrolled into the upper part of the viewport; every occurrence inside a message counts toward `n/N`
14
- - **Sticky group headers** — while scrolling the outline, the header of the turn you are inside stays pinned to the top of the panel, flush against the toolbar above it
15
- - **Position breadcrumb** — the top of the panel shows the path of the section you are reading (e.g. `Deploy › Docker`). The rule is "the deepest heading above the viewport's middle line", i.e. the section that fills most of the screen; clicking it keeps showing that same heading afterwards, because a jump also lands above the middle line. When you do not want that row, the **位置 (position)** button just left of the magnifier collapses it (the choice is remembered)
16
- - **Heading level filter** — the `1`–`6` chips in the panel header are **independent switches**, so any combination is possible (e.g. H1 and H3 with H2 hidden); the choice is remembered. Switching off the last remaining level restores all six, so the panel is never empty. That row itself can be collapsed: the **层级 (levels)** button at the left of the magnifier hides/shows it (the choice is remembered), and the filter keeps applying while it is hidden
17
- - **Code blocks are not headings** — `# comment` / `## example` lines inside a ``` fenced code block never become outline entries (they used to leak into the outline and made the real headings after them jump to the wrong place)
18
- - **Auto-follow highlighting** — while scrolling the conversation, the turns visible in the viewport light up in the outline (several at once) and the rest dim; the outline loads and scrolls so the group being read stays visible
19
- - **Jumping** — click a heading to jump to its position in the conversation, or click a group header's time/preview to jump to the **start of that turn's model reply**
20
- - **Dockable and resizable** — drag the top bar to move the panel, use ◀ / ▶ to dock it left or right, drag an edge or corner to resize, and collapse it into an edge handle (click it to expand); the panel's position and size are remembered
21
- - **Paging and loading older** — the most recent groups show first; scrolling up inside the outline loads older groups
22
- - **Markdown-aware titles** — inline markup in headings (`**bold**`, `*italic*`, `` `code` ``, `[links](url)`, `~~strike~~`) is stripped before display
23
- - **Chat view only** — when the center column switches to another view (trajectory, context, …), the panel and its edge handle fade out
24
- - When the conversation has no headings at all, the outline lists clickable turn-time entries only; it hides itself when not even a time can be read. It adapts to the dark and light themes (the inner-shadow card follows the theme)
9
+ - **Turn-grouped outline** — each user message plus its following AI replies form one group; the group header shows the turn's time and a first-line preview, and clicking it jumps to the start of that turn's model reply
10
+ - **Whole-session coverage** — turns the conversation window has not loaded are listed too (tagged 未加载, with previews); clicking one loads that turn and jumps to it
11
+ - **Row subtitles** — under each heading, the first sentence of that section, so identically-titled headings can be told apart
12
+ - **Hover previews** — hovering a heading row shows the section's opening, the turn time and the heading path
13
+ - **Search** — title / full-text scopes; click any result row to locate and highlight that hit, `n/N` Enter stepping, Esc to close
14
+ - **Search tolerance** — case, full-width/half-width and whitespace differences match automatically; the "fuzzy" switch also allows a little material wedged between keywords
15
+ - **In-chat highlighting** — matched keywords are highlighted in the conversation; the current match is highlighted distinctly
16
+ - **Sticky group headers** — while scrolling the outline, the current turn's header stays pinned at the top of the panel
17
+ - **Heading level filter** — the round levels button in the header pops down H1–H6 switches for any combination
18
+ - **Auto-follow** — the turn being read lights up in a closed blue box while you scroll the conversation; the outline follows on its own
19
+ - **Jumping** — click a heading to jump to its position in the conversation
20
+ - **Dockable and resizable** — drag the top bar to move the panel, ◀ / ▶ to dock left or right, drag an edge to resize, and collapse it into an edge handle; position and size are remembered
21
+ - **Paging** — the most recent groups show first; scrolling up both expands the index and loads older conversation
22
+ - **Edge hints** — a brief hint at the bottom of the panel when you keep scrolling past the first or the last entry
23
+ - **Markdown-aware** — inline markup in headings is stripped; `#` lines inside fenced code blocks are not headings
24
+ - **Theme-aware** adapts to dark and light themes; visible on the chat view only and fades out elsewhere
25
+ - The panel hides itself when the conversation has neither headings nor readable times
25
26
 
26
27
  ## Compatibility
27
28
 
28
29
  | Plugin | Supported DSH |
29
30
  | --- | --- |
30
- | **0.4.0** (latest) | 0.1.5-rc.1, 0.1.5-rc.2 |
31
+ | **0.5.0** (latest) | 0.1.5-rc.1, 0.1.5-rc.2 |
32
+ | 0.4.1 | 0.1.5-rc.1, 0.1.5-rc.2 |
33
+ | 0.4.0 | 0.1.5-rc.1, 0.1.5-rc.2 |
31
34
  | 0.3.3 | 0.1.5-rc.1 |
32
35
  | 0.3.0 – 0.3.2 | ≥ 0.1.2-rc.1 |
33
36
 
34
- `engines.dsh` has a floor of **0.1.5-rc.1** (`>=`): from that release on, the plugin uses the host's session-scoped slot injection. 0.4.0 has been verified against **0.1.5-rc.1 and 0.1.5-rc.2** and declares exactly those; older or newer DSH versions are unverified and therefore not claimed. On an older DSH, the newest usable plugin version is **0.3.2**. On install or update, the DSH market pre-flights host compatibility from `engines.dsh`, `dsh.compatibility.dshReleases` and `peerDependencies` in `package.json`.
37
+ `engines.dsh` has a floor of **0.1.5-rc.1** (`>=`): from that release on, the plugin uses the host's session-scoped slot injection. 0.5.0 was tested on **0.1.5-rc.2**, and the host interfaces it newly relies on (the `turnOutline` projection, the session-scoped `useProjection`, the client `sessions` service and its `loadThrough` jump loader) were checked one by one against the installed **0.1.5-rc.1** bundles, so both are declared. Older or newer DSH versions are unverified and therefore not claimed; on an older DSH the newest usable plugin version is **0.3.2**. On install or update, the DSH market pre-flights host compatibility from `engines.dsh`, `dsh.compatibility.dshReleases` and `peerDependencies` in `package.json`.
35
38
 
36
39
  ## Install
37
40
 
@@ -57,12 +60,14 @@ After installing, restart DSH and open the Web UI. The panel starts collapsed; c
57
60
 
58
61
  ## Usage
59
62
 
60
- - **Jumping**: click a heading in the outline to jump to its position; click a group header's time or first-line preview to jump to the **start of that turn's model reply**; click the breadcrumb at the top to jump to the heading you are inside
61
- - **Search**: click the magnifier in the header to open the search box; once you type a keyword the outline becomes a result list — click any row to locate and highlight that hit, or press Enter to step through the matches (`n/N` shows the current position and the total, and the row holding the current match is highlighted); press Esc or the magnifier again to close and return to the outline; use the **title / full-text** button to change the search scope
62
- - **Level filter**: the `1`–`6` chips are independent switches, so any combination works; the **层级 (levels)** button in the header collapses or expands that row
63
- - **Moving and docking**: drag the top bar to move the panel; use ◀ / ▶ to switch between left and right docking
64
- - **Resizing**: drag the right edge for width, the bottom edge for height, or the bottom-right corner for both
65
- - **Loading older turns**: scroll up inside the outline to load older groups; when the conversation itself offers a "load older messages" button, the outline also triggers it on reaching the top
63
+ - **Jumping**: click an outline heading or a group header to jump to it; entries tagged 未加载 load that turn first
64
+ - **Search**: open the box with the magnifier, click a result to locate and highlight it, Enter to step through matches, Esc to close
65
+ - **Search tolerance**: full-width/half-width, case and whitespace differences match automatically; for looser matching turn on the "fuzzy" switch next to the search box
66
+ - **Level filter**: click the round levels button in the header to pop down the H1–H6 switches
67
+ - **Moving and docking**: drag the top bar to move, / to switch sides
68
+ - **Resizing**: drag the right edge, bottom edge or bottom-right corner
69
+ - **Loading older turns**: scroll up inside the outline (it both expands the index and loads older conversation)
70
+ - **Reading position**: scroll the conversation and the turn you are reading is boxed in blue; the outline follows
66
71
 
67
72
  ## Development
68
73
 
@@ -70,7 +75,8 @@ After installing, restart DSH and open the Web UI. The panel starts collapsed; c
70
75
  - `lib/index.js` — host-side entry (empty; this plugin ships browser-side UI only)
71
76
  - `cordis.patch.yml` — loader patch (official DSH bundle format)
72
77
  - The panel registers into the session-scoped `conversation.input.overlay` slot so it receives session-scoped hooks (`useChat`, `useSession`, `sessionId`, …), and renders itself through `createPortal` into `document.body` as a fixed floating dock; conversation data comes from `props.useChat` (`ChatSnapshot.order` and `nodes`; node shape: `kind: user/assistant-step`, `location.turn`, `data.blocks`)
73
- - Changes to `lib/client.js` take effect after restarting DSH
78
+ - The "unloaded turn" capability needs two host facilities: the `turnOutline` projection (the whole-session turn index, each entry carrying its `turn/start` seq) and the turn-jump loader (the client `sessions` service's `binding(sessionId).session.loadThrough(seq)`, reached through the client ctx's declaration-free `ctx.get("sessions")` lookup). Each degrades on its own: without the projection the outline lists loaded turns only, without the loader unloaded entries are shown but not jumped to, and nothing else in the panel is affected.
79
+ - Changes to `lib/client.js` show up after a page refresh (client modules are served under a content hash and DSH's client HMR pushes reloads); restart DSH only if that does not take
74
80
 
75
81
  ## License
76
82
 
package/README.md CHANGED
@@ -2,36 +2,39 @@
2
2
 
3
3
  > [English](README.en.md) | **中文**
4
4
 
5
- **DeepSeek Harness(DSH)对话大纲插件**:把 AI 回复中的 Markdown 标题(H1–H6)提取成可导航的大纲面板,按对话回合分组,自动跟随阅读位置,支持关键字搜索与对话内高亮定位。
5
+ **DeepSeek Harness(DSH)对话大纲插件**:把 AI 回复中的 Markdown 标题(H1–H6)提取成可导航的大纲面板,按对话回合分组、覆盖整段会话(含尚未加载进窗口的回合),支持标题/全文搜索、悬停预览与阅读位置自动跟随。
6
6
 
7
7
  ## 功能
8
8
 
9
- - **按回合分组** —— 每条用户消息 + 其后续 AI 回复为一组;组头显示该组最后一条消息的结束时间,并附带该回合首行预览,点击跳到**该回合模型回答的开头**(没有标题的回合只剩这一行,同样可点)
10
- - **关键字搜索** —— 标题栏放大镜打开搜索框;输入后按 **回车** 跳到下一处命中(循环),按 **Esc** 关闭;命中计数以 `n/N` 显示
11
- - **搜索结果列表** —— 输入关键字后,大纲切换为结果列表:每行是命中的标题或消息(关键字高亮),并显示层级路径、回合时间与重复次数(全文搜索时附上下文片段)。列表按时间顺序排(**最新的命中在底部**),开始搜索时自动定位到最新命中,向上滚即可回看更早的命中;**点击任一行**把该命中设为当前命中——与回车逐处跳走同一条路径,会在对话里高亮并滚动过去
12
- - **搜索范围切换** —— 搜索框内的 **标题 / 全文** 按钮切换范围:仅标题,或同时搜索用户消息与 AI 回复正文
13
- - **对话内高亮** —— 命中的关键字在对话中高亮,当前命中单独标亮并滚动到视口上部;同一条消息中的多次命中都会计入 `n/N`
14
- - **组头吸顶** —— 滚动大纲时,当前所在回合的组头固定在面板顶部(与上方工具条紧贴,中间不留空隙),始终知道自己在看哪一轮
15
- - **位置提示(面包屑)** —— 面板顶部显示你正在读的章节路径(如 `部署 › Docker`)。判定规则是"**视口中线之上最深的那个标题**",也就是画面里占得最多的那一节;点击它跳过去后仍显示同一个标题(跳转落点也在中线之上,规则自洽)
16
- - **层级筛选** —— 面板顶部的 `1`–`6` 芯片是**各自独立的开关**,可任意组合(例如只留 H1 和 H3、关掉中间的 H2);选择会被记住。把最后一个还亮着的层级也关掉时,会自动恢复显示全部六级(面板不会变空)。这一行本身也能收起:标题栏里放大镜左边的 **层级** 按钮收起/展开它(选择会记住),收起后筛选设置仍然生效
17
- - **代码块不算标题** —— ``` 围栏代码块里的 `# 注释`、`## 示例` 不会被当成大纲标题(以前会混进大纲,还会让它后面那些真标题跳错位置)
18
- - **自动跟随高亮** —— 滚动对话时,视口内可见的回合在大纲中自动点亮(可同时点亮多组),其余组变暗;大纲自动加载并滚动,使正在阅读的组保持可见
19
- - **跳转** —— 点击标题跳到对话中该标题所在位置;点击组头的时间或预览跳到该回合开头
20
- - **可停靠、可缩放** —— 拖顶部横条移动,按 / ▶ 切换左右停靠,拖边缘或角部调整宽高,收起后成为边缘把手(点击展开);面板位置与尺寸会被记住
21
- - **分页与加载更早** —— 默认显示最近的若干组;在大纲中向上滚动(或滚动到顶部)会加载更早的组
22
- - **Markdown 清理** —— 标题中的行内标记(`**加粗**`、`*斜体*`、`` `代码` ``、`[链接](url)`、`~~删除线~~`)会被剥离后显示
23
- - **仅对话视图显示** —— 中间列切到轨迹、上下文等其他视图时,面板与边缘把手渐隐
24
- - 对话中没有任何标题时,大纲只列出可点击跳转的回合时间条目;连时间也识别不到时面板自动隐藏。适配深色与浅色主题(内阴影质感随主题切换)
9
+ - **按回合分组** —— 每条用户消息 + 其后续 AI 回复为一组,组头显示回合时间与首行预览,点击跳到该回合模型回答的开头
10
+ - **覆盖整段会话** —— 未加载进对话窗口的回合也在列表里(带「未加载」标记与预览);点击即加载该回合并跳过去
11
+ - **标题行副标题** —— 每行标题下方显示该节正文的第一句,同名标题一眼可辨
12
+ - **悬停预览** —— 悬停标题行显示该节开头、回合时间与层级路径
13
+ - **搜索** —— 标题 / 全文两种范围,结果列表点击定位并高亮,`n/N` 回车逐处跳,Esc 关闭
14
+ - **搜索容错** —— 大小写、全角半角、连续空白自动视为同一匹配;「模糊」开关可放宽到关键字中间夹字
15
+ - **对话内高亮** —— 命中的关键字在对话中高亮,当前命中单独标亮
16
+ - **组头吸顶** —— 滚动大纲时,当前回合的组头固定在面板顶部
17
+ - **层级筛选** —— 标题栏的圆形层级按钮弹出 H1–H6 开关,任意组合显示
18
+ - **自动跟随** —— 滚动对话时正在阅读的回合自动点亮(封闭蓝框),大纲自动跟随
19
+ - **跳转** —— 点击标题跳到对话中该标题的位置;面板与对话双向定位
20
+ - **可停靠、可缩放** —— 拖顶部横条移动,◀ / ▶ 切换左右停靠,拖边缘调宽高,收起后成为边缘把手;位置与尺寸会被记住
21
+ - **分页** —— 默认显示最近的若干组,向上滚动既展开索引也加载更早的对话
22
+ - **边界提示** —— 滚到最早或最新再继续滚动时,面板底部短暂提示
23
+ - **Markdown 感知** —— 标题中的行内标记会被剥离;围栏代码块里的 `#` 行不算标题
24
+ - **主题适配** —— 深色 / 浅色主题自适应;仅对话视图显示,切到其他视图渐隐
25
+ - 对话中没有标题也没有可识别时间时面板自动隐藏
25
26
 
26
27
  ## 兼容性
27
28
 
28
29
  | 插件版本 | 支持的 DSH 版本 |
29
30
  | --- | --- |
30
- | **0.4.0**(最新) | 0.1.5-rc.1、0.1.5-rc.2 |
31
+ | **0.5.0**(最新) | 0.1.5-rc.1、0.1.5-rc.2 |
32
+ | 0.4.1 | 0.1.5-rc.1、0.1.5-rc.2 |
33
+ | 0.4.0 | 0.1.5-rc.1、0.1.5-rc.2 |
31
34
  | 0.3.3 | 0.1.5-rc.1 |
32
35
  | 0.3.0 – 0.3.2 | ≥ 0.1.2-rc.1 |
33
36
 
34
- `engines.dsh` 下限为 **0.1.5-rc.1**(`>=`,该版本起插件改用会话级槽位注入的宿主接口);0.4.0 在 **0.1.5-rc.1 0.1.5-rc.2** 上验证过并声明兼容,更早或更新的 DSH 版本未经验证,不作声明。在更早的 DSH 上,可安装的最新插件版本是 **0.3.2**。安装或更新时,DSH 市场会依据 `package.json` 中的 `engines.dsh`、`dsh.compatibility.dshReleases` 与 `peerDependencies` 做宿主兼容预检。
37
+ `engines.dsh` 下限为 **0.1.5-rc.1**(`>=`,该版本起插件改用会话级槽位注入的宿主接口)。0.5.0 在 **0.1.5-rc.2** 上实测通过;它新依赖的宿主接口(`turnOutline` 投影、会话级槽位的 `useProjection`、客户端 `sessions` 服务与 `loadThrough` 跳转加载器)已在 **0.1.5-rc.1** 的安装包中逐个核对存在,因此两版都声明兼容。更早或更新的 DSH 版本未经验证,不作声明;在更早的 DSH 上可安装的最新插件版本是 **0.3.2**。安装或更新时,DSH 市场会依据 `package.json` 中的 `engines.dsh`、`dsh.compatibility.dshReleases` 与 `peerDependencies` 做宿主兼容预检。
35
38
 
36
39
  ## 安装
37
40
 
@@ -57,12 +60,14 @@ dsh plugin --profile web add <插件目录路径>
57
60
 
58
61
  ## 使用
59
62
 
60
- - **跳转**:点击大纲标题跳到该标题所在位置;点击组头的时间或首行预览跳到**该回合模型回答的开头**;点击顶部的面包屑跳到当前所在标题
61
- - **搜索**:点击标题栏的放大镜展开搜索框,输入关键字后大纲切换为结果列表——直接点某一条定位并高亮,或按回车逐处循环(`n/N` 显示当前位置与命中总数,当前命中所属行会高亮);按 Esc 或再次点击放大镜关闭并回到大纲;用 **标题 / 全文** 按钮切换搜索范围
62
- - **层级筛选**:`1`–`6` 芯片是各自独立的开关,可任意组合;点标题栏的 **层级** 按钮收起/展开这一行
63
- - **移动与停靠**:拖顶部横条移动面板,按 / ▶ 在左右之间切换停靠
64
- - **调整大小**:拖右边缘调宽度、拖下边缘调高度、拖右下角同时调整
65
- - **加载更早**:在大纲中向上滚动即可加载更早的回合;对话本身有"加载更早消息"按钮时,大纲滚到顶部也会触发它
63
+ - **跳转**:点击大纲标题或组头跳到对应位置;带「未加载」标记的条目会先把该回合加载进来再跳
64
+ - **搜索**:放大镜打开搜索框,输入后点结果定位并高亮,回车逐处跳,Esc 关闭
65
+ - **搜索容错**:全角/半角、大小写、空格差异会自动匹配;需要更宽松时点搜索框右侧的「模糊」开关
66
+ - **层级筛选**:点标题栏的圆形层级按钮弹出 H1–H6 开关,选择显示的层级
67
+ - **移动与停靠**:拖顶部横条移动,◀ / ▶ 切换左右停靠
68
+ - **调整大小**:拖右边缘、下边缘或右下角
69
+ - **加载更早**:在大纲中向上滚动(既展开索引,也加载更早的对话)
70
+ - **阅读位置**:滚动对话,正在阅读的回合会以蓝框标出;大纲会自动跟随
66
71
 
67
72
  ## 开发
68
73
 
@@ -70,7 +75,8 @@ dsh plugin --profile web add <插件目录路径>
70
75
  - `lib/index.js` —— 宿主端入口(空实现;本插件只提供浏览器端 UI)
71
76
  - `cordis.patch.yml` —— loader patch(符合官方 bundle 规范)
72
77
  - 面板注册进会话级 `conversation.input.overlay` 槽以取得会话级 hook(`useChat`、`useSession`、`sessionId` 等),面板本体通过 `createPortal` 渲染到 `document.body` 成为固定浮层;对话数据来自 `props.useChat`(`ChatSnapshot.order` 与 `nodes`,节点形状:`kind: user/assistant-step`、`location.turn`、`data.blocks`)
73
- - 修改 `lib/client.js` 后需重启 DSH 生效
78
+ - 「未加载回合」能力依赖宿主的两样东西:`turnOutline` 投影(整段会话的回合索引,每条含 `turn/start` seq)与会话跳转加载器(客户端 `sessions` 服务的 `binding(sessionId).session.loadThrough(seq)`,通过客户端 ctx 的 `ctx.get("sessions")` 免声明查找取得)。两者各自独立降级:没有投影时只列已加载回合,没有加载器时未加载条目只展示、不跳转,面板其余功能不受影响。
79
+ - 修改 `lib/client.js` 后刷新页面即可看到变化(客户端模块按内容哈希发版,DSH 的客户端 HMR 也会推送重载);若未生效再重启 DSH
74
80
 
75
81
  ## License
76
82