dsh-turn-navigator 0.4.2 → 0.4.4
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 +22 -0
- package/CONTRIBUTING.md +10 -0
- package/README.md +24 -15
- package/README.zh.md +23 -14
- package/lib/client.js +25 -8
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.4] - 2026-09-22
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Live disable/reload no longer leaves the OFFICIAL rail hidden.** The plugin hides the built-in rail with a `tn-hide-official` class on `document.body`, but nothing removed that class when the plugin unloaded. dsh 0.1.6-alpha.2 enables the host `hmr` row by default for launcher-provided profiles, so the dsh Plugins page can now disable or reload a bundle **without a restart** — with the stale class the official rail stayed hidden after the plugin was gone, and only a page reload brought it back. The class is now applied inside `ctx.effect(...)` and removed by its dispose hook (`clearModeFromBody`), so unloading restores the built-in default — `src/client/index.ts`, `src/client/mode.ts`.
|
|
8
|
+
|
|
9
|
+
- **The release gate no longer fails on proxied networks.** `release-check.mjs` probed the registry with Node's `fetch`, which ignores npm's `.npmrc` proxy settings — and the proxy variables plus `NODE_USE_ENV_PROXY` are sampled when the process starts (verified on Node 24.18: setting them inside the script changes nothing), so the probe went **direct**. On 2026-09-22 three probe timeouts blocked the 0.4.4 publish with `The operation was aborted due to timeout`, while `npm publish` itself (which does honor `.npmrc`) would have worked. The probe now runs `npm view` — the same registry, proxy and auth as the publish it guards. `post-publish-check.mjs` gets the same treatment for its curl fallbacks (registry probes and the tarball download), preferring npm's configured proxy over an inherited variable so the check actually verifies instead of degrading to "unreachable" — `scripts/release-check.mjs`, `scripts/post-publish-check.mjs`.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **Two stale `dsh.client.inject` entries removed** — `@deepseek-ai/dsh-client-runtime` and `@deepseek-ai/dsh-client-web-react`. Neither package exists in the current dsh client graph (the former was removed upstream in dsh 0.1.2, per the 0.4.2 entry below) and this plugin's source never imported either one; `inject` names package rows to order against, so listing absent rows was dead weight. The remaining six entries are unchanged.
|
|
14
|
+
|
|
15
|
+
### Tests
|
|
16
|
+
|
|
17
|
+
- **New `scripts/test-client-dispose.mjs`, wired into `pnpm test`.** It loads the real built `lib/client.js` in a minimal DOM + module-loader stub and asserts the observable contract: `apply()` hides the official rail through the body class, and the registered cordis effect's disposer restores it. Verified as a real gate by negative control — replacing the `ctx.effect(...)` wrapper with a bare `applyModeToBody()` makes it fail.
|
|
18
|
+
|
|
19
|
+
## [0.4.3] - 2026-09-06
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- **Brand naming standardized**: the product is now **Smoothly Turn Nav**(简称 **Smoothly TN**,品牌英文 **Smoothly** / 品牌中文 **思磨力**;中文名 **思磨力轮次胶囊条**),replacing the previous "DSH Smoothly Turn Nav (DSH STN)". Applied everywhere user-visible: bilingual README (title, features, comparison table, version map, usage, compatibility), `package.json` description + keywords, the Settings → General *Turn navigation* rail-mode labels (`Smoothly TN` / `思磨力轮次胶囊条`), code comments, and the verify-mode acceptance assertion. **Technical identifiers are intentionally unchanged and decoupled from the brand**: npm package name, plugin/slot IDs, locale namespace, CSS prefix, and the localStorage mode key all remain `dsh-turn-navigator` — installed profiles, persisted preferences, and the bundle URL are untouched. Historical documents (`docs/official-vs-ours.md`, past changelog entries) keep their original naming.
|
|
24
|
+
|
|
3
25
|
## [0.4.2] - 2026-09-05
|
|
4
26
|
|
|
5
27
|
### Docs
|
package/CONTRIBUTING.md
CHANGED
|
@@ -21,6 +21,16 @@ Every release must be done in one pass: code + bilingual README + CHANGELOG + ve
|
|
|
21
21
|
7. `npm publish` (requires 2FA; the agent cannot do this step).
|
|
22
22
|
8. `postpublish` runs `scripts/post-publish-check.mjs` automatically.
|
|
23
23
|
|
|
24
|
+
## The release gates use npm's own transport
|
|
25
|
+
|
|
26
|
+
`release-check.mjs` asks `npm view` whether the version is already published, and
|
|
27
|
+
`post-publish-check.mjs` gives its curl fallbacks npm's configured proxy — both on
|
|
28
|
+
purpose. Node's `fetch` cannot be proxied after startup (the proxy variables and
|
|
29
|
+
`NODE_USE_ENV_PROXY` are sampled at process start) and ignores `.npmrc` entirely, so
|
|
30
|
+
a fetch-based gate goes direct and blocks every release on a network where the
|
|
31
|
+
registry is only reachable through the proxy in `.npmrc` — even though
|
|
32
|
+
`npm publish` itself would work. Keep new registry access on the npm/curl path.
|
|
33
|
+
|
|
24
34
|
## npm publish is manual (2FA)
|
|
25
35
|
|
|
26
36
|
npm accounts with two-factor authentication require an OTP that the agent cannot provide. The agent prepares everything to "one command to publish"; the human runs `npm login` → `npm publish`.
|
package/README.md
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Smoothly Turn Nav (Smoothly TN)
|
|
2
|
+
|
|
3
|
+
**Smoothly · 思磨力** — brand · 中文名:**思磨力轮次胶囊条**
|
|
2
4
|
|
|
3
5
|
**English · [简体中文](README.zh.md)**
|
|
4
6
|
|
|
5
7
|
**Every turn of your conversation, one glance away.**
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
Smoothly Turn Nav (**Smoothly TN**) — 思磨力轮次胶囊条 — is an external plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh) that puts a **piano-key turn rail** on the right edge of every conversation — a vertical column of tiny capsules, one per turn. It gives you a full minimap of the conversation: **every turn ever made** (not just the ones currently loaded), hover previews, click-to-jump to any turn's start, and follow-scroll highlighting. It can also **replace the official built-in turn rail**, which has no off-switch of its own.
|
|
8
10
|
|
|
9
11
|

|
|
10
12
|
|
|
11
13
|
## Why
|
|
12
14
|
|
|
13
|
-
In the default DSH web UI, the official turn rail historically showed only the **currently loaded window** of turns — in a long conversation, most turns are invisible until you scroll and load more. As of dsh **0.1.3-alpha.1** the built-in rail also gained full-session scope and out-of-window jumps through a host-side `turnOutline` projection, but it still **cannot be switched off**.
|
|
15
|
+
In the default DSH web UI, the official turn rail historically showed only the **currently loaded window** of turns — in a long conversation, most turns are invisible until you scroll and load more. As of dsh **0.1.3-alpha.1** the built-in rail also gained full-session scope and out-of-window jumps through a host-side `turnOutline` projection, but it still **cannot be switched off**. Smoothly TN solves the long-session problem and stays fully replaceable:
|
|
14
16
|
|
|
15
17
|
- **Full history at a glance** — every persisted turn is shown as plain data, including turns far outside the loaded window. No scrolling, no loading, no waiting.
|
|
16
18
|
- **Hover to preview** — the capsule glows with the theme color and widens in a wave ripple; a DSH-style tooltip shows the turn's number, time, and user-message summary.
|
|
@@ -28,16 +30,17 @@ In the default DSH web UI, the official turn rail historically showed only the *
|
|
|
28
30
|
| 🎯 **Jump to any turn** | Precise `scrollTop` targeting (no `scrollIntoView` fights); out-of-window jumps extend the window on demand with a "Locating turn N…" pulse + bubble; the oldest-turn jump loads to the **true first turn** (`hasMore = false`) |
|
|
29
31
|
| 👁️ **Follow-scroll highlight** | The capsule of the turn at the reading line is tinted as you scroll — and the rail's own viewport keeps the active turn in view |
|
|
30
32
|
| ⬆️⬇️ **Scroll buttons** | Click or hover-hold to scroll the rail; greyed out when there is nothing to scroll |
|
|
31
|
-
| 🎛️ **Rail mode switch** | Settings → General → *Turn navigation*: `DSH official` / `
|
|
33
|
+
| 🎛️ **Rail mode switch** | Settings → General → *Turn navigation*: `DSH official` / `Smoothly TN` (default) / `Hide all` — persisted across reloads, so the official rail can finally be **turned off** |
|
|
32
34
|
| 🔌 **Pure external plugin** | No DSH source code modified; no host changes; no new dependencies; read-only DOM access |
|
|
33
35
|
|
|
34
36
|
## vs. the official DSH turn rail
|
|
35
37
|
|
|
36
|
-
The official built-in `TurnNavigator` has **no off-switch** and is always rendered in the chat view. The table below compares it at **dsh 0.1.3-alpha.1** (the current DSH web `TurnNavigator`, which re-added full-session scope via its own host projection) against this plugin, **
|
|
38
|
+
The official built-in `TurnNavigator` has **no off-switch** and is always rendered in the chat view. The table below compares it at **dsh 0.1.3-alpha.1** (the current DSH web `TurnNavigator`, which re-added full-session scope via its own host projection) against this plugin, **Smoothly TN v0.4.3**:
|
|
37
39
|
|
|
38
|
-
| Capability | DSH official rail (0.1.3-alpha.1) |
|
|
40
|
+
| Capability | DSH official rail (0.1.3-alpha.1) | Smoothly TN (v0.4.3) |
|
|
39
41
|
|---|---|---|
|
|
40
42
|
| Turns shown | **Every turn** — host `turnOutline` projection (0.1.3+) | Every persisted turn — **client-side** journal read |
|
|
43
|
+
| Full-history robustness | Depends on the host `turnOutline` projection — **not driven** by browser-synthesized sessions (e.g. `?fixture`), where it falls back to the loaded window | Always full — reads the persisted journal directly, no host projection required (verified full on both real and fixture sessions) |
|
|
41
44
|
| How full history is read | Host-side projection embedded in the snapshot | Client pages the persisted journal (`session/page`); older dsh falls back to `sessions.history` RPC — **zero host changes** |
|
|
42
45
|
| Jump to a turn outside the window | ✅ (0.1.3+ unloaded anchor pages history by seq) | ✅ on-demand window extension + "Locating turn N…" pulse/bubble |
|
|
43
46
|
| Long-session open performance | Reads the projection | **Zero prepend** — plain data, no flow re-render, no stall |
|
|
@@ -51,19 +54,23 @@ The official built-in `TurnNavigator` has **no off-switch** and is always render
|
|
|
51
54
|
| Keyboard accessibility | ✅ focus ring + `aria-current`/`aria-busy`/`aria-describedby` | ✅ focusable buttons (`Turn N — time — summary` aria-label) |
|
|
52
55
|
| Source | Built-in, cannot be disabled | External plugin, **can be replaced/disabled** |
|
|
53
56
|
|
|
54
|
-
As of dsh 0.1.3 the built-in rail caught up on full-session scope and out-of-window jumps. What still sets
|
|
57
|
+
As of dsh 0.1.3 the built-in rail caught up on full-session scope and out-of-window jumps. What still sets Smoothly TN apart: you can **switch it off** (the official rail cannot), the tooltip carries the **timestamp + full summary**, there are **scroll buttons and wave hover**, and it remains an **external, read-only plugin with zero host changes**. And on dsh ≤ 0.1.2 the built-in rail is simpler still (loaded window only), so the gap Smoothly TN closes is even larger there.
|
|
58
|
+
|
|
59
|
+
**Verified on dsh 0.1.3-alpha.1 (2026-09-06, Playwright against the live web UI)**: on a real 42-turn session both rails show all 42 turns (the official one via its host projection, ours via the journal); on a `?fixture` browser-synthesized session the official rail degrades to the loaded window (24/75) while Smoothly TN still shows all 75 — because our full history never depends on the host projection. Jumps, follow-scroll highlight, the mode switch, and the subtractive takeover of the official rail (`display: none` via the stylesheet override) all verified working.
|
|
55
60
|
|
|
56
61
|
## Version map
|
|
57
62
|
|
|
58
|
-
Which
|
|
63
|
+
Which Smoothly TN release matches which dsh:
|
|
59
64
|
|
|
60
|
-
|
|
|
65
|
+
| Smoothly TN | dsh | Notes |
|
|
61
66
|
|---|---|---|
|
|
62
67
|
| v0.1.x | dsh ≤ 0.1.1 | Full history via the legacy `sessions.history` browser→host RPC |
|
|
63
68
|
| v0.2.x – v0.4.1 | dsh 0.1.2+ | Adapted to the `ui-chat` refactor; full history via the journal `session/page` channel; v0.4.1 fixed true turn numbers and rail-viewport follow |
|
|
64
|
-
| **v0.4.2** | dsh 0.1.2+, incl. **0.1.3-alpha.1** |
|
|
69
|
+
| **v0.4.2** | dsh 0.1.2+, incl. **0.1.3-alpha.1** | Comparison/positioning updated against the 0.1.3 official rail (see above) |
|
|
70
|
+
| **v0.4.3** | dsh 0.1.2+, incl. **0.1.3-alpha.1** | This release: brand naming standardized to **Smoothly**(思磨力)/ **Smoothly Turn Nav**(**Smoothly TN**)/ **思磨力轮次胶囊条** — technical IDs (npm package `dsh-turn-navigator`, plugin/slot IDs, locale namespace, CSS prefix, localStorage key) unchanged |
|
|
71
|
+
| **v0.4.4** | dsh 0.1.2+, client contract re-checked against **0.1.6-alpha.2** | This release: the official-rail body class gained a dispose hook (disabling or reloading the bundle live from the dsh Plugins page restores the built-in rail), and two stale `inject` entries are gone |
|
|
65
72
|
|
|
66
|
-
The official-rail comparison in this README targets **dsh 0.1.3-alpha.1**; on older dsh the official rail is simpler, so
|
|
73
|
+
The official-rail comparison in this README targets **dsh 0.1.3-alpha.1**; on older dsh the official rail is simpler, so Smoothly TN's advantage is larger there.
|
|
67
74
|
|
|
68
75
|
## Installation
|
|
69
76
|
|
|
@@ -79,7 +86,7 @@ dsh web
|
|
|
79
86
|
|
|
80
87
|
## Usage
|
|
81
88
|
|
|
82
|
-
0. **Choose which rail to show** (Settings → General → **Turn navigation**): `DSH official` (the built-in rail), `
|
|
89
|
+
0. **Choose which rail to show** (Settings → General → **Turn navigation**): `DSH official` (the built-in rail), `Smoothly TN` (this plugin's rail — **default**), or `Hide all`. The official rail has no off-switch, so choosing Smoothly TN hides it with a stylesheet override and our rail takes over the right-edge center position. The choice persists across reloads.
|
|
83
90
|
1. Open any conversation with at least one completed turn.
|
|
84
91
|
2. A vertical rail of grey capsules appears on the right edge (one per turn). It **auto-sizes** — short conversations get a short rail, long ones hit the 30vh cap and scroll internally (hidden scrollbar, no layout jitter).
|
|
85
92
|
3. **Hover** a capsule: it glows, widens in a wave, and shows the turn's **number, timestamp, and summary** in a tooltip to the left of the rail.
|
|
@@ -103,14 +110,16 @@ The plugin registers **two additive slots** — **no DSH source code is modified
|
|
|
103
110
|
|
|
104
111
|
## Compatibility
|
|
105
112
|
|
|
106
|
-
- DeepSeek Harness (dsh) with the web client (`dsh web`); developed and verified against dsh 0.1.2+ and
|
|
113
|
+
- DeepSeek Harness (dsh) with the web client (`dsh web`); developed and verified against dsh 0.1.2+ and **verified against dsh 0.1.3-alpha.1** (Playwright re-test, 2026-09-06: full-history rail, jumps, follow highlight, mode switch, and the official-rail stylesheet takeover all passing).
|
|
107
114
|
- Requires the `conversation.session.header.utilities` and `settings.general.item` slot declarations (present in current DSH).
|
|
108
|
-
-
|
|
115
|
+
- Client contract re-checked against **dsh 0.1.6-alpha.2** (2026-09-22): the `conversation.session.header.utilities`, `settings.general.item` and `shell.overlay` slot declarations, the `ui-primitives` exports the rail uses, and the `--dsw-alias-*` tokens it references all still exist. The interactive Playwright re-test was **not** re-run on 0.1.6 (the 2026-09-06 run remains the last interactive verification).
|
|
116
|
+
- Default `Smoothly TN` mode hides the official rail (stylesheet override) and centers our rail in its place; `DSH official` mode shows the built-in rail instead; `Hide all` hides both. Both rails auto-hide below 900px width.
|
|
109
117
|
- Coexists with full-screen plugin pages (e.g. the kanban board): the rail sits below their overlay layer.
|
|
110
118
|
|
|
111
119
|
## Development
|
|
112
120
|
|
|
113
|
-
- `pnpm typecheck`
|
|
121
|
+
- `pnpm typecheck` — TypeScript check (tsdown does not typecheck).
|
|
122
|
+
- `pnpm test` — typecheck plus `scripts/test-client-dispose.mjs`, which loads the built bundle in a DOM stub and asserts the apply/dispose contract of the official-rail body class.
|
|
114
123
|
- `pnpm bundle` — build the module-table client bundle into `lib/`.
|
|
115
124
|
- `scripts/verify-*.mjs` — Playwright acceptance scripts against a live `dsh web` (rail, full-history journal, mode switch, jump, feedback, overlay, sizing, UI).
|
|
116
125
|
- `pnpm release:check` — release gates (version, tag, tree, build, registry).
|
package/README.zh.md
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 思磨力轮次胶囊条(Smoothly Turn Nav)
|
|
2
|
+
|
|
3
|
+
**思磨力 · Smoothly** — 品牌 · 英文名:**Smoothly Turn Nav**(简称 **Smoothly TN**)
|
|
2
4
|
|
|
3
5
|
**[English](README.md) · 简体中文**
|
|
4
6
|
|
|
5
7
|
**整场会话,一眼纵览。**
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
思磨力轮次胶囊条(**Smoothly Turn Nav**,简称 **Smoothly TN**)是 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(dsh)的外部插件,在每条会话右侧放一条**钢琴键式轮次胶囊条**——竖向一列小胶囊,一轮一个。它是整场会话的迷你地图:**全部历史轮次一目了然**(不只是当前已加载的窗口),悬停预览、点击跳转到任意轮次起点、滚动跟随高亮。它还可以**取代官方内置轮次胶囊条**(官方没有自己的关闭开关)。
|
|
8
10
|
|
|
9
11
|

|
|
10
12
|
|
|
11
13
|
## 为什么需要
|
|
12
14
|
|
|
13
|
-
默认 DSH Web UI 的官方轮次胶囊条**历史上**只显示**当前已加载窗口内**的轮次——长会话里,大部分轮次要滚动加载后才可见。从 dsh **0.1.3-alpha.1** 起,官方胶囊条也通过宿主侧 `turnOutline`
|
|
15
|
+
默认 DSH Web UI 的官方轮次胶囊条**历史上**只显示**当前已加载窗口内**的轮次——长会话里,大部分轮次要滚动加载后才可见。从 dsh **0.1.3-alpha.1** 起,官方胶囊条也通过宿主侧 `turnOutline` 投影补上了紧要的全会话范围与窗口外跳转,但它依然**无法关闭**。思磨力轮次胶囊条解决长会话问题,并且始终可替换:
|
|
14
16
|
|
|
15
17
|
- **全量历史一眼可见**——所有持久化轮次以纯数据呈现,包括远在已加载窗口之外的轮次。不滚动、不加载、不等待。
|
|
16
18
|
- **悬停即预览**——胶囊以主题色亮起并泛起波浪涟漪;DSH 风格 Tooltip 展示该轮序号、时间与用户消息摘要。
|
|
@@ -28,16 +30,17 @@ DSH Smoothly Turn Nav(**DSH STN**)是 [DeepSeek Harness](https://github.com/
|
|
|
28
30
|
| 🎯 **跳转任意轮** | 精确 `scrollTop` 定位(不与 `scrollIntoView` 打架);窗口外跳转按需扩展窗口并显示"正在定位第 N 轮…"脉冲+气泡;最老轮次跳转加载到**真正第一轮**(`hasMore = false`) |
|
|
29
31
|
| 👁️ **滚动跟随高亮** | 阅读线所在轮次的胶囊随滚动点亮——且胶囊条自身视口会跟随当前轮次保持可见 |
|
|
30
32
|
| ⬆️⬇️ **滚动按钮** | 点击或悬停持续滚动;无可滚动内容时置灰 |
|
|
31
|
-
| 🎛️ **胶囊条模式开关** | 设置 → 通用 → *轮次导航*:`DSH 官方` /
|
|
33
|
+
| 🎛️ **胶囊条模式开关** | 设置 → 通用 → *轮次导航*:`DSH 官方` / `思磨力轮次胶囊条`(默认)/ `全部隐藏`——跨刷新持久保存,官方胶囊条终于可以**关掉** |
|
|
32
34
|
| 🔌 **纯外部插件** | 不改 DSH 源码;零宿主改动;零新增依赖;仅只读 DOM |
|
|
33
35
|
|
|
34
36
|
## 与官方 DSH 轮次胶囊条对比
|
|
35
37
|
|
|
36
|
-
官方内置 `TurnNavigator` **没有关闭开关**,始终渲染在会话视图里。下表对比对象为 **dsh 0.1.3-alpha.1**(当前 DSH Web 的 `TurnNavigator`,该版也通过自己的宿主投影恢复了全会话范围)与本插件
|
|
38
|
+
官方内置 `TurnNavigator` **没有关闭开关**,始终渲染在会话视图里。下表对比对象为 **dsh 0.1.3-alpha.1**(当前 DSH Web 的 `TurnNavigator`,该版也通过自己的宿主投影恢复了全会话范围)与本插件 **思磨力轮次胶囊条 v0.4.3**:
|
|
37
39
|
|
|
38
|
-
| 能力 | DSH 官方胶囊条(0.1.3-alpha.1) |
|
|
40
|
+
| 能力 | DSH 官方胶囊条(0.1.3-alpha.1) | 思磨力轮次胶囊条(v0.4.3) |
|
|
39
41
|
|---|---|---|
|
|
40
42
|
| 显示的轮次 | **全部轮次**——宿主 `turnOutline` 投影(0.1.3+) | 全部持久化轮次——**客户端**读取 journal |
|
|
43
|
+
| 全量历史的健壮性 | 依赖宿主 `turnOutline` 投影——**浏览器合成会话**(如 `?fixture`)不驱动投影,此时退回"仅加载窗口" | 始终全量——直接读持久化日志,无需宿主投影(真实会话与 fixture 会话均已实测全量) |
|
|
41
44
|
| 全会话历史怎么读 | 宿主侧投影内嵌在会话快照里 | 客户端分页读持久化日志(`session/page`);旧版 dsh 退回 `sessions.history` RPC——**零宿主改动** |
|
|
42
45
|
| 跳转窗口外轮次 | ✅(0.1.3+ 未加载锚点按 seq 分页) | ✅ 按需扩展窗口 + "正在定位第 N 轮…"脉冲/气泡 |
|
|
43
46
|
| 长会话打开性能 | 读投影 | **零 prepend**——纯数据、不重渲染会话流、不卡顿 |
|
|
@@ -51,19 +54,23 @@ DSH Smoothly Turn Nav(**DSH STN**)是 [DeepSeek Harness](https://github.com/
|
|
|
51
54
|
| 键盘可达 | ✅ 焦点环 + `aria-current`/`aria-busy`/`aria-describedby` | ✅ 可聚焦按钮(aria-label=`Turn N — 时间 — 摘要`) |
|
|
52
55
|
| 来源 | 内置、无法关闭 | 外部插件,**可替换 / 可关闭** |
|
|
53
56
|
|
|
54
|
-
dsh 0.1.3
|
|
57
|
+
dsh 0.1.3 起官方胶囊条已在紧要的全会话范围与窗口外跳转上追平。**思磨力轮次胶囊条仍然独占的**:可以**关掉它**(官方关不掉)、Tooltip 带**时间戳与完整摘要**、**滚动按钮 + 波浪悬停**、以及它始终是**零宿主改动的外部只读插件**。在 dsh ≤ 0.1.2 上官方胶囊条更简单(仅加载窗口),思磨力轮次胶囊条填补的差距更大。
|
|
58
|
+
|
|
59
|
+
**dsh 0.1.3-alpha.1 实测(2026-09-06,Playwright 直连在线 Web UI)**:真实 42 轮会话上两个胶囊条都显示全部 42 轮(官方走宿主投影、我们走 journal);`?fixture` 浏览器合成会话上官方胶囊条退化为"仅加载窗口"(24/75),而思磨力轮次胶囊条仍显示全部 75——因为我们的全量历史从不依赖宿主投影。跳转、滚动跟随高亮、模式开关、以及减法接管官方胶囊条(样式覆盖 `display: none`)均实测通过。
|
|
55
60
|
|
|
56
61
|
## 版本对照
|
|
57
62
|
|
|
58
63
|
我们的版本与 dsh 版本的对应关系:
|
|
59
64
|
|
|
60
|
-
|
|
|
65
|
+
| 思磨力轮次胶囊条 | dsh | 说明 |
|
|
61
66
|
|---|---|---|
|
|
62
67
|
| v0.1.x | dsh ≤ 0.1.1 | 通过旧版 `sessions.history` 浏览器→宿主 RPC 读全量历史 |
|
|
63
68
|
| v0.2.x – v0.4.1 | dsh 0.1.2+ | 适配 `ui-chat` 重构;通过 journal `session/page` 通道读全量历史;v0.4.1 修复真实轮次号与胶囊条视口跟随 |
|
|
64
|
-
| **v0.4.2** | dsh 0.1.2+(含 **0.1.3-alpha.1**) |
|
|
69
|
+
| **v0.4.2** | dsh 0.1.2+(含 **0.1.3-alpha.1**) | 对照 dsh 0.1.3 官方胶囊条更新对比与定位(见上文) |
|
|
70
|
+
| **v0.4.3** | dsh 0.1.2+(含 **0.1.3-alpha.1**) | 本版:品牌命名规范化为 **Smoothly**(思磨力)/ **Smoothly Turn Nav**(**Smoothly TN**)/ **思磨力轮次胶囊条**——技术标识符(npm 包名 `dsh-turn-navigator`、插件/slot ID、locale 命名空间、CSS 前缀、localStorage key)不变 |
|
|
71
|
+
| **v0.4.4** | dsh 0.1.2+,客户端契约对照 **0.1.6-alpha.2** 复核 | 本版:官方胶囊条的 body class 补上 dispose(从 dsh 插件页在线停用/重载后会恢复内置胶囊条);清掉两个陈旧 `inject` 条目 |
|
|
65
72
|
|
|
66
|
-
本文 README 的对比对象为 **dsh 0.1.3-alpha.1**;在更旧的 dsh
|
|
73
|
+
本文 README 的对比对象为 **dsh 0.1.3-alpha.1**;在更旧的 dsh 上官方胶囊条更简单,思磨力轮次胶囊条的优势更大。
|
|
67
74
|
|
|
68
75
|
## 安装
|
|
69
76
|
|
|
@@ -79,7 +86,7 @@ dsh web
|
|
|
79
86
|
|
|
80
87
|
## 使用
|
|
81
88
|
|
|
82
|
-
0. **选择显示哪个胶囊条**(设置 → 通用 → **轮次导航**):`DSH 官方`(内置 rail
|
|
89
|
+
0. **选择显示哪个胶囊条**(设置 → 通用 → **轮次导航**):`DSH 官方`(内置 rail)、`思磨力轮次胶囊条`(本插件 rail——**默认**)、或`全部隐藏`。官方 rail 没有关闭开关,选择思磨力轮次胶囊条时以样式覆盖将其隐藏,我们的 rail 接管右缘居中位置。选择会跨刷新持久保存。
|
|
83
90
|
1. 打开任意包含至少一轮已完成轮次的会话。
|
|
84
91
|
2. 会话右侧出现一条竖向灰色胶囊列(每轮一个)。胶囊条**长度自适应**:轮次少则短,轮次多则达 30vh 上限后内部滚动(滚动条隐藏,无布局抖动)。
|
|
85
92
|
3. **悬停**某个胶囊:它以主题色亮起并泛起波浪、向左加宽,胶囊条左侧弹出 Tooltip(**序号、时间、摘要**),始终完整在视口内。
|
|
@@ -103,14 +110,16 @@ dsh web
|
|
|
103
110
|
|
|
104
111
|
## 兼容性
|
|
105
112
|
|
|
106
|
-
- DeepSeek Harness (dsh) Web 客户端(`dsh web`);基于 dsh 0.1.2+
|
|
113
|
+
- DeepSeek Harness (dsh) Web 客户端(`dsh web`);基于 dsh 0.1.2+ 开发与实测,并在 **dsh 0.1.3-alpha.1 上复测通过**(Playwright 直连实测,2026-09-06:全量历史胶囊条、跳转、跟随高亮、模式开关、官方胶囊条样式接管全部通过)。
|
|
107
114
|
- 需要 `conversation.session.header.utilities` 与 `settings.general.item` slot 声明(当前 DSH 已包含)。
|
|
108
|
-
-
|
|
115
|
+
- 客户端契约已对照 **dsh 0.1.6-alpha.2** 复核(2026-09-22):`conversation.session.header.utilities`、`settings.general.item`、`shell.overlay` 的 slot 声明、胶囊条用到的 `ui-primitives` 导出、以及它引用的 `--dsw-alias-*` token 均仍存在。0.1.6 上的 Playwright 交互复测**未重跑**(2026-09-06 那次仍是最近一次交互验证)。
|
|
116
|
+
- 默认 `思磨力轮次胶囊条` 模式以样式覆盖隐藏官方 rail,我们的 rail 居中接管;`DSH 官方` 模式显示内置 rail;`全部隐藏` 两者皆隐。900px 以下都自动隐藏。
|
|
109
117
|
- 与全屏插件页面(如看板)共存:胶囊条层级位于全屏 overlay 之下。
|
|
110
118
|
|
|
111
119
|
## 开发
|
|
112
120
|
|
|
113
|
-
- `pnpm typecheck`
|
|
121
|
+
- `pnpm typecheck` — TypeScript 检查(tsdown 只转译不检查)。
|
|
122
|
+
- `pnpm test` — 类型检查 + `scripts/test-client-dispose.mjs`:在 DOM 桩里加载构建产物,断言官方胶囊条 body class 的 apply/dispose 契约。
|
|
114
123
|
- `pnpm bundle` — 构建模块表 client bundle 到 `lib/`。
|
|
115
124
|
- `scripts/verify-*.mjs` — 针对真实 `dsh web` 的 Playwright 验收脚本(rail、全量历史 journal、模式开关、跳转、反馈、overlay、尺寸、UI)。
|
|
116
125
|
- `pnpm release:check` — 发布门禁(版本、tag、工作树、构建、registry)。
|
package/lib/client.js
CHANGED
|
@@ -371,6 +371,20 @@ window.__ModuleLoader__.load({
|
|
|
371
371
|
if (typeof document === "undefined") return;
|
|
372
372
|
document.body.classList.toggle("tn-hide-official", current !== "official");
|
|
373
373
|
}
|
|
374
|
+
/**
|
|
375
|
+
* Drop the `tn-hide-official` body class — the plugin's dispose hook.
|
|
376
|
+
*
|
|
377
|
+
* dsh 0.1.6+ enables the host `hmr` row by default for launcher-provided
|
|
378
|
+
* profiles, so this plugin can be disabled or reloaded LIVE (the dsh Plugins
|
|
379
|
+
* page toggles bundles without a restart). Without this teardown the class
|
|
380
|
+
* outlives the plugin and keeps hiding the OFFICIAL rail, and only a page
|
|
381
|
+
* reload brings it back. Removing the class is the correct "unloaded" state:
|
|
382
|
+
* the official rail is the built-in default whenever this plugin is not applied.
|
|
383
|
+
*/
|
|
384
|
+
function clearModeFromBody() {
|
|
385
|
+
if (typeof document === "undefined") return;
|
|
386
|
+
document.body.classList.remove("tn-hide-official");
|
|
387
|
+
}
|
|
374
388
|
//#endregion
|
|
375
389
|
//#region src/client/TurnNavRail.tsx
|
|
376
390
|
/**
|
|
@@ -848,7 +862,7 @@ window.__ModuleLoader__.load({
|
|
|
848
862
|
* the General section renders each contribution as one row, so this component
|
|
849
863
|
* draws its own title, description, and a three-way selector:
|
|
850
864
|
*
|
|
851
|
-
* DSH official |
|
|
865
|
+
* DSH official | Smoothly TN (Smoothly Turn Nav) | Hide all
|
|
852
866
|
*
|
|
853
867
|
* The choice is persisted browser-locally (see mode.ts) and drives both the
|
|
854
868
|
* rail component (React-side visibility) and the official-rail stylesheet
|
|
@@ -915,7 +929,7 @@ window.__ModuleLoader__.load({
|
|
|
915
929
|
}
|
|
916
930
|
//#endregion
|
|
917
931
|
//#region src/client/locales.ts
|
|
918
|
-
/** Copy dictionaries for the dsh-turn-navigator plugin (
|
|
932
|
+
/** Copy dictionaries for the dsh-turn-navigator plugin (Smoothly Turn Nav / 思磨力轮次胶囊条). */
|
|
919
933
|
/** English strings (the key-set source of truth for this pair). */
|
|
920
934
|
const en = {
|
|
921
935
|
rail: "Turn navigation",
|
|
@@ -924,9 +938,9 @@ window.__ModuleLoader__.load({
|
|
|
924
938
|
locatingTurn: "Locating turn {n}…",
|
|
925
939
|
locateFailed: "Could not locate turn {n}",
|
|
926
940
|
modeRowTitle: "Turn navigation",
|
|
927
|
-
modeRowDesc: "Which turn-navigation rail to display: the DSH built-in,
|
|
941
|
+
modeRowDesc: "Which turn-navigation rail to display: the DSH built-in, Smoothly TN (Smoothly Turn Nav), or none.",
|
|
928
942
|
modeOfficial: "DSH official",
|
|
929
|
-
modeSTN: "
|
|
943
|
+
modeSTN: "Smoothly TN",
|
|
930
944
|
modeHidden: "Hide all"
|
|
931
945
|
};
|
|
932
946
|
/** Chinese strings (same keys as {@link en}). */
|
|
@@ -937,9 +951,9 @@ window.__ModuleLoader__.load({
|
|
|
937
951
|
locatingTurn: "正在定位第 {n} 轮…",
|
|
938
952
|
locateFailed: "无法定位第 {n} 轮",
|
|
939
953
|
modeRowTitle: "轮次导航",
|
|
940
|
-
modeRowDesc: "选择显示哪个轮次胶囊条:DSH
|
|
954
|
+
modeRowDesc: "选择显示哪个轮次胶囊条:DSH 官方、思磨力轮次胶囊条(Smoothly Turn Nav),或全部隐藏。",
|
|
941
955
|
modeOfficial: "DSH 官方",
|
|
942
|
-
modeSTN: "
|
|
956
|
+
modeSTN: "思磨力轮次胶囊条",
|
|
943
957
|
modeHidden: "全部隐藏"
|
|
944
958
|
};
|
|
945
959
|
//#endregion
|
|
@@ -989,7 +1003,7 @@ window.__ModuleLoader__.load({
|
|
|
989
1003
|
display: none;
|
|
990
1004
|
}
|
|
991
1005
|
}
|
|
992
|
-
/* Subtractive takeover (settings → Turn navigation =
|
|
1006
|
+
/* Subtractive takeover (settings → Turn navigation = Smoothly TN): hide the
|
|
993
1007
|
OFFICIAL built-in rail. The official rail lives inside the conversation
|
|
994
1008
|
scroll container (data-conversation-scroll) — our rail is fixed outside
|
|
995
1009
|
it — so a container-scoped rule cannot match ours. The tn-hide-official
|
|
@@ -1262,7 +1276,10 @@ body.tn-hide-official [data-conversation-scroll] nav {
|
|
|
1262
1276
|
}), "dsh-turn-navigator: copy dictionaries");
|
|
1263
1277
|
const t = ctx.locale.bind(NS);
|
|
1264
1278
|
const api = ctx.get("connection")?.api;
|
|
1265
|
-
|
|
1279
|
+
ctx.effect(() => {
|
|
1280
|
+
applyModeToBody();
|
|
1281
|
+
return clearModeFromBody;
|
|
1282
|
+
}, "dsh-turn-navigator: official-rail body class");
|
|
1266
1283
|
let journal;
|
|
1267
1284
|
let sessionAccess;
|
|
1268
1285
|
const resolveHandles = () => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-turn-navigator",
|
|
3
|
-
"version": "0.4.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.4.4",
|
|
4
|
+
"description": "Smoothly Turn Nav (Smoothly TN): full-history piano-key turn rail for DeepSeek Harness (dsh) web conversations — see every turn at a glance, hover to preview, click to jump anywhere, and replace the official (non-disableable) turn rail.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -32,11 +32,9 @@
|
|
|
32
32
|
"inject": [
|
|
33
33
|
"@deepseek-ai/dsh-client-connection",
|
|
34
34
|
"@deepseek-ai/dsh-client-locale",
|
|
35
|
-
"@deepseek-ai/dsh-client-runtime",
|
|
36
35
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
37
36
|
"@deepseek-ai/dsh-client-ui-layout",
|
|
38
37
|
"@deepseek-ai/dsh-client-ui-slots",
|
|
39
|
-
"@deepseek-ai/dsh-client-web-react",
|
|
40
38
|
"@deepseek-ai/dsh-api-remotes"
|
|
41
39
|
],
|
|
42
40
|
"platform": "web"
|
|
@@ -46,7 +44,7 @@
|
|
|
46
44
|
"bundle": "tsdown --config ./tsdown.config.ts",
|
|
47
45
|
"prepare": "tsdown --config ./tsdown.config.ts",
|
|
48
46
|
"typecheck": "tsc --noEmit",
|
|
49
|
-
"test": "tsc --noEmit",
|
|
47
|
+
"test": "tsc --noEmit && node scripts/test-client-dispose.mjs",
|
|
50
48
|
"release:check": "node scripts/release-check.mjs",
|
|
51
49
|
"prepack": "node scripts/release-check.mjs",
|
|
52
50
|
"prepublishOnly": "node scripts/release-check.mjs && tsdown --config ./tsdown.config.ts",
|
|
@@ -65,8 +63,10 @@
|
|
|
65
63
|
"outline",
|
|
66
64
|
"turn-rail",
|
|
67
65
|
"turn-navigator",
|
|
66
|
+
"smoothly",
|
|
67
|
+
"思磨力",
|
|
68
68
|
"smoothly-turn-nav",
|
|
69
|
-
"
|
|
69
|
+
"smoothly-tn"
|
|
70
70
|
],
|
|
71
71
|
"author": "karoc",
|
|
72
72
|
"license": "MIT",
|