@konnga/dsh-hud 0.9.0 → 0.9.1

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/README.en.md ADDED
@@ -0,0 +1,176 @@
1
+ # dsh-hud
2
+
3
+ [![release](https://img.shields.io/npm/v/%40konnga%2Fdsh-hud?label=release&color=fb8c00)](https://www.npmjs.com/package/@konnga/dsh-hud) [![node](https://img.shields.io/badge/node-%3E%3D20-43853d?logo=nodedotjs&logoColor=white)](#install) [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
4
+
5
+ **English** | [中文](./README.md)
6
+
7
+ A read-only DeepSeek Harness status panel: branch, ahead/behind, changed files and diffs — plus which files *this session* touched, what you have reviewed, and what tools ran.
8
+
9
+ > Screenshots in this file were taken in the **Chinese UI**; the plugin's own labels follow your UI language, and every quoted label below is the English one you would actually see.
10
+
11
+ ![The three capsules above the composer: Git status on the left, tools & skills in the middle, this session's running time on the right](docs/images/capsules.webp)
12
+
13
+ ## Install
14
+
15
+ Desktop: **Settings → Plugins → Add plugin**, then enter `@konnga/dsh-hud`.
16
+
17
+ For local development, point the profile at the checkout (host changes apply immediately; client code is re-read on app restart):
18
+
19
+ ```json
20
+ "@konnga/dsh-hud": "link:/path/to/dsh-hud"
21
+ ```
22
+
23
+ ## What it gives you
24
+
25
+ | Feature | In one line | Where |
26
+ | --- | --- | --- |
27
+ | **Git capsule** | Workspace name, branch, ahead/behind, change counts, files this session touched | Leftmost of the row above the composer (click to open the panel) |
28
+ | **Tools capsule** | What is running now (live seconds), per-tool call counts, skills used | Same row, middle |
29
+ | **Session timer capsule** | How long this session has been running; hover for model/tool wall time and turns | Same row, rightmost |
30
+ | **Panel** | Change overview, change list, recent commits, tags; click any row for its diff | Click the Git capsule |
31
+ | **Diffs, commit detail, images** | Unstaged / staged, word wrap, copy diff; image side-by-side + zoom | Right of the panel, draggable |
32
+ | **Per-turn image changes** | Images touched this turn: click to view one, `⇄` for before/after | Next to the built-in "edited N files" card |
33
+ | **Sidebar session rows** | Hover or click `⋯` to expand: git summary + per-session attribution | Every sidebar session row |
34
+ | **Keyboard** | `↑↓` `Enter` `[ ]` `n p` `Space` `v` `r` `Esc` inside the panel | Once the panel is active |
35
+ | **`↑` prompt recall** | Empty composer + `↑` brings back your previous prompt | In the composer |
36
+
37
+ ## What you will see
38
+
39
+ ### Capsules (the row above the composer)
40
+
41
+ ```
42
+ dsh-hud · git:(main*) ↑1 ↓2 M4 A1 ?1 │ ●3 │ ✓ bash ×16 │ … │ ⏱ 2h 14m
43
+ ```
44
+
45
+ > Hover tips on all three capsules are **bubbles the plugin draws itself** — not the browser's native tooltip, which never showed up in the real app and whose delay and styling we cannot control anyway.
46
+
47
+ **Git** (leftmost)
48
+
49
+ - `dsh-hud` — workspace name (elided in the middle when long; hover for the full path). Shown even outside a git repository.
50
+ - `git:(main*)` — branch. `*` means the worktree is dirty; detached shows `git:(detached abc1234)`.
51
+ - `↑1 ↓2` — ahead/behind the upstream (hidden when zero).
52
+ - `M4 A1 ?1` — change counts, only non-zero ones: `M` modified · `A` added · `D` deleted · `R` renamed · `C` copied · `T` type change · `?` untracked · `!` conflicted.
53
+ - `●3` — this session changed 3 files (hidden when there are none).
54
+
55
+ **Tools** (middle, appears once a tool has run)
56
+
57
+ ```
58
+ ◐ bash: pnpm test 1.2s ← running, seconds tick live
59
+ ✓ bash ×16 │ ✓ apply_patch ×6 │ skills: office-xlsx ×2 +2 ← idle
60
+ ```
61
+
62
+ - One count per tool; the leading `✓` / `✗` is the result of **its own most recent** call.
63
+ - After `skills:` come skill *names* (so you can tell which skill, not just how many calls).
64
+ - At most 3 tools + 2 skills are laid out; the rest collapse into `+k`. Hover for the full list and the latest results.
65
+
66
+ **Session timer** (rightmost)
67
+
68
+ ```
69
+ ⏱ 2h 14m
70
+ ```
71
+
72
+ - **How long this session has been running.** Same definition as [codex-hud](https://github.com/konnga/codex-hud)'s session duration: `now − session createdAt` (idle time included). Format: `<1m` / `45m` / `2h 14m` / `3d 2h`.
73
+ - Hover adds what actually happened during that time:
74
+
75
+ ```
76
+ This session's running time · started 2026-10-14 17:58 · model 1h 29m, tools 23m · 27 turns / 380 steps
77
+ ```
78
+
79
+ The last two come from the built-in `sessionStats` projection; when that projection is absent we show the wall clock only and invent nothing.
80
+ - Right after a restart it may be missing for a few seconds: the session is restored into the host store asynchronously (measured: about 30 s). So a failed lookup is retried every **3 s** and drops to once a minute once it succeeds. If the session is archived or the host has no `sessions` service, the capsule is not drawn at all.
81
+
82
+ Here it is on a real machine:
83
+
84
+ ![Hovering the session timer capsule: a bubble above it reads the session's running time, when it started, the model and tool wall time, and the turn and step counts, with the capsule itself "⏱ 4d 16h 31m" below](docs/images/pill-tip.webp)
85
+
86
+ *The same bubble is used by the Git and tools capsules (the Git one is multi-line: full path / upstream / per-type counts).*
87
+
88
+ ### Panel (click the Git capsule)
89
+
90
+ ![The panel: change overview and this session's changes, change list, recent commits and tags on the left; the selected commit's files in the middle; the diff on the right](docs/images/panel.webp)
91
+
92
+ *Above: viewing a commit. The title bar is draggable; `⟳` refresh · `⌖` reset position · `✕` collapse.*
93
+
94
+ 1. **Repository path · upstream · short oid**
95
+ 2. **Summary** — coloured counts grouped by kind; says `Working tree clean — nothing uncommitted` when it is.
96
+ 3. **This session's changes** — one line of counts plus the toggles `Only this session's` and `Latest turn only`; with review marks you also get `3/8 reviewed` and `Clear reviewed`.
97
+ 4. **Changes** — each row is `marker status-letter path`, renames read as `old → new`.
98
+ - Leading `●` definitely changed · `◐` possibly changed (inferred from a command; hover shows that command) · `○` unrelated to this session.
99
+ - Trailing `○` / `✓` is the review mark — click it or press `v`; `✓` turning yellow means the file changed again and needs another look.
100
+ - Click any row for that file's diff.
101
+ 5. **Recent commits** — `shortsha subject [HEAD] 2026-10-16 14:18`; click a row to view that commit, click again to collapse.
102
+ 6. **Tags** — newest first; click a row to view the commit it points at. A repository without tags says so.
103
+
104
+ Every timestamp is a **full date + time** in your local zone.
105
+
106
+ ### Diffs, commit detail and images
107
+
108
+ - **Diff view**: two columns, toolbar with `Unstaged` / `Staged` / `Wrap lines` / `Copy diff`; click a hunk header to fold that hunk.
109
+ - **Commit view**: three columns — panel │ commit │ diff — and it opens the commit's first file for you.
110
+ - **Two grips to drag**: the one on the right edge sets the diff width (default 470px), the one right of the commit column sets that column's width (default 240px). Both widths are remembered.
111
+ - **Image changes**: files recognised as images (PNG / JPEG / GIF / WebP / BMP, **by file header, not by extension**) are drawn side by side with size and byte deltas (`size 1024×768 → 1024×512`, `2.0 KB → 1.0 KB`). When an image cannot be drawn the reason is stated: over the 4 MB per-side limit, not a previewable image, or that side missing (added / deleted).
112
+ - **Image zoom**: an always-visible `−` / step / `+`, defaulting to fit-width, with steps 25% / 50% / 100% / 150% / 200% computed from the image's intrinsic pixels; clicking the step itself returns to fit-width. The step is remembered.
113
+
114
+ ![An image change in the diff column: the toolbar, then a "side by side" toggle and − 100% + zoom buttons, an amber "size 190×140 → 230×160" and "8.8 KB → 11.4 KB", and two images side by side labelled "index" and "worktree"](docs/images/image-diff.webp)
115
+
116
+ ### Per-turn image changes
117
+
118
+ ![Per-turn image changes: three thumbnails, two of them marked ◐ because they were inferred from commands, each followed by a ⇄, ending with "3 more"](docs/images/turn-images.webp)
119
+
120
+ The built-in "edited N files" card cannot show images, so the plugin puts its own door on that same turn tail:
121
+
122
+ - click a thumbnail → open that image in the built-in document preview on the right;
123
+ - click `⇄` → open this plugin's panel for a **before/after** comparison (the built-in preview only has the current version);
124
+ - only images touched **in this turn** are listed, newest first, up to 4 plus `N more`; when a turn touched no images the whole strip is not rendered;
125
+ - both attribution tiers are included: files written by tools count as certain, ones inferred from shell commands are marked `◐` (hover shows the command) — images are usually produced by scripts, so certain-only would often be empty.
126
+
127
+ ### Sidebar session rows
128
+
129
+ The sidebar row itself carries no marks; the information is in the hover card or behind the row-end `⋯`:
130
+
131
+ ```
132
+ main* ↑0 ↓0 · modified 7 untracked 2
133
+ 3 file(s) changed by this session · 4 path(s) commands may have touched (1 still differ)
134
+ ```
135
+
136
+ When clean it says `Working tree clean — nothing uncommitted` and `this session has no recorded changes`.
137
+
138
+ ### Keyboard
139
+
140
+ **Click inside the panel first** (or Tab into it) before it takes over keys; clicking outside hands them back. Cmd/Ctrl/Alt combinations and keys typed in the composer are never touched.
141
+
142
+ | Key | Action |
143
+ | --- | --- |
144
+ | `↑` `↓` | Move the selected row (move only, does not open) |
145
+ | `Enter` | Open the selected row |
146
+ | `[` `]` | Previous / next file, opening it right away |
147
+ | `n` `p` | Next / previous hunk (folded ones expand) |
148
+ | `Space` | Fold / unfold the current hunk |
149
+ | `v` | Mark the current row as reviewed for this revision (press again to clear) |
150
+ | `r` | Re-read |
151
+ | `Esc` | Step back: collapse the right column (diff / commit) first, then the panel |
152
+
153
+ While viewing commit detail, `↑ ↓ Enter [ ]` act on that column's list.
154
+
155
+ ### `↑` in the composer recalls your previous prompt
156
+
157
+ With the composer empty, `↑` brings back your previous prompt; keep pressing to walk further back, `↓` walks forward, and stepping past the newest returns you to your original draft.
158
+
159
+ - **Plain text only**: `/commands` and `@files` are text already, so they come back intact; attachments and images do not come back (they were never part of the prompt text).
160
+ - **Sourced from the session log** (the built-in `turnOutline` projection), not from a copy the plugin keeps — so restarts, paging and compaction do not affect it, and **prompts sent from another client can be recalled too**. If the host lacks that projection, the whole feature silently stays off.
161
+ - **It never takes over while the composer has content**, so `↑` in a multi-line draft is always just cursor movement, and it cannot fight the `/` command or `@` mention popups. Modifier keys, IME composition and a non-collapsed selection all make it step aside.
162
+ - Typing exits history mode, so a draft is never restored over new content.
163
+
164
+ > Implementation note: DSH's composer is a Lexical `contenteditable`, and a plugin cannot reach its internal model — so we simulate a paste (falling back to `execCommand`, then to writing text directly), and each tier re-reads the composer after the write has landed before deciding it succeeded. This is the only part of the plugin that touches the DOM; if DSH changes that structure it may stop working, in which case it silently disables itself.
165
+
166
+ ## Development
167
+
168
+ - `lib/index.js` — the host half (runs git, serves `/dsh-hud-rpc`).
169
+ - `lib/client.js` — the browser half (**no build step**, hand-written JS, depends only on the seed module `react`).
170
+ - `npm test` — the whole suite (`node --test test/*.test.mjs`). No dependencies to install.
171
+ - `docs/dock-slot-host.md` — a proposal for turning the row above the composer into a registrable inline host.
172
+ - **Releasing**: `npm run tag && npm publish`. `prepublishOnly` runs the tests and then verifies version ↔ git tag (clean tree, `v<version>` exists and points at HEAD); a mismatch blocks the publish.
173
+
174
+ ## License
175
+
176
+ MIT
package/README.md CHANGED
@@ -1,11 +1,12 @@
1
1
  # dsh-hud
2
2
 
3
- > 一个只读的工作区 Git 面板:分支、ahead/behind、改动清单与差异,外加「这个会话改过哪些文件、审到哪了、跑了什么工具」。
4
- > A read-only workspace Git panel for DeepSeek Harness, with per-session change attribution.
3
+ [![release](https://img.shields.io/npm/v/%40konnga%2Fdsh-hud?label=release&color=fb8c00)](https://www.npmjs.com/package/@konnga/dsh-hud) [![node](https://img.shields.io/badge/node-%3E%3D20-43853d?logo=nodedotjs&logoColor=white)](#安装) [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
4
 
6
- ![输入框上方的两枚胶囊:左边是 Git 状态,右边是工具与技能](docs/images/capsules.webp)
5
+ [English](./README.en.md) | **中文**
7
6
 
8
- *左:工作区名 · `git:(分支*)` · ahead/behind · 改动计数 · 本会话改过几个文件。右:每个工具的调用次数、正在跑什么、以及会话调用过哪些技能 —— 图中 `aihot ×1` 是红的,因为那次调用失败了。*
7
+ DeepSeek HUD 状态面板:分支、ahead/behind、改动清单与差异,外加「这个会话改过哪些文件、审到哪了、跑了什么工具」。
8
+
9
+ ![输入框上方的三枚胶囊:左边是 Git 状态,中间是工具与技能,最右边是本次会话运行时长](docs/images/capsules.webp)
9
10
 
10
11
  ## 安装
11
12
 
@@ -17,121 +18,154 @@
17
18
  "@konnga/dsh-hud": "link:/path/to/dsh-hud"
18
19
  ```
19
20
 
21
+ ## 功能总览
22
+
23
+ | 功能 | 一句话 | 在哪儿 |
24
+ | ------------------------------ | ----------------------------------------------------------------------- | ------------------------------------ |
25
+ | **Git 胶囊** | 工作区名、分支、ahead/behind、改动计数、本会话改过几个文件 | 输入框上方那一行,最左(点它开面板) |
26
+ | **工具胶囊** | 正在跑什么(实时秒数)、各工具调用次数、用过的技能 | 同一行,中间 |
27
+ | **会话计时胶囊** | 本次会话已运行多久;悬停给模型 / 工具墙钟与轮次 | 同一行,最右 |
28
+ | **面板** | 改动概览、改动清单、最近提交、标签;点任意一行看差异 | 点 Git 胶囊 |
29
+ | **差异与提交明细** | 未暂存 / 已暂存、自动换行、复制差异;图片并排对比 + 缩放 | 面板右侧,可拖动 |
30
+ | **轮尾「本轮图片改动」** | 这一轮动过的图:点开看单张,`⇄` 看前后对比 | 内置「已编辑 N 个文件」卡片旁 |
31
+ | **侧栏会话行** | 悬停或点 `⋯` 展开:git 摘要 + 本会话归因 | 侧栏每个会话行 |
32
+ | **键盘** | 面板内 `↑↓` `Enter` `[ ]` `n p` `Space` `v` `r` `Esc` | 面板激活后 |
33
+ | **输入框 `↑` 召回** | 空输入框按 `↑` 带回上一条 prompt | 输入框里 |
34
+
20
35
  ## 你会看到什么
21
36
 
22
- ### 胶囊(输入框上方)
37
+ ### 胶囊(输入框上方那一行)
23
38
 
24
39
  ```
25
- dsh-hud · git:(main*) ↑1 ↓2 M4 A1 ?1 │ ●3
40
+ dsh-hud · git:(main*) ↑1 ↓2 M4 A1 ?1 │ ●3 │ ✓ bash ×16 │ … │ ⏱ 2h 14m
26
41
  ```
27
42
 
28
- - `dsh-hud` —— 工作区名(当前会话的目录名)。太长从中间省略,完整路径看悬停。
43
+ > 三枚胶囊的**悬停提示是插件自己画的气泡**(不用浏览器原生 tooltip —— 它在真机上不出现,延迟与样式也控制不了)。
44
+
45
+ **Git**(最左)
46
+
47
+ - `dsh-hud` —— 工作区名(太长从中间省略,完整路径看悬停)。不在 git 仓库里也会显示。
29
48
  - `git:(main*)` —— 分支。`*` 表示工作区不干净;detached 时是 `git:(detached abc1234)`。
30
49
  - `↑1 ↓2` —— 与上游的领先 / 落后(为 0 不显示)。
31
- - `M4 A1 ?1` —— 改动计数,只列非零项:`M` 修改 · `A` 新增 · `D` 删除 · `R` 重命名 · `C` 复制 · `T` 类型改变 · `?` 未跟踪 · `!` 冲突。
50
+ - `M4 A1 ?1` —— 改动计数,只列非零项:`M` 改 · `A` 增 · `D` 删 · `R` 重命名 · `C` 复制 · `T` 类型 · `?` 未跟踪 · `!` 冲突。
32
51
  - `●3` —— 本会话改过 3 个文件(没有就不显示)。
33
52
 
34
- 点它开面板;悬停给出完整路径、上游与各类计数。**不在 git 仓库里也会显示**(只有工作区名 + `git:(非 git 仓库)`)。
35
-
36
- ### 工具胶囊(同一行的右边,只在跑过工具后出现)
53
+ **工具**(中间,运行过的工具才出现)
37
54
 
38
55
  ```
39
- ◐ bash: pnpm test 1.2s ← 正在跑(秒数实时跳)
56
+ ◐ bash: pnpm test 1.2s ← 正在跑,秒数实时跳
40
57
  ✓ bash ×16 │ ✓ apply_patch ×6 │ skills: office-xlsx ×2 +2 ← 空闲
41
58
  ```
42
59
 
43
- - 每个工具一个计数;前面的 `✓` / `✗` 是**它自己最近一次调用**的结果。
44
- - `skills:` 后面是会话调用过的**技能名**(不是"技能调了几次"—— 看得出是哪一个)。
45
- - 最多铺 3 个工具、2 个技能,其余收成 `+k`;悬停里有完整清单与最近几条的执行结果。
60
+ - 每个工具一个计数,前面的 `✓` / `✗` 是**它自己最近一次**调用的结果。
61
+ - `skills:` 后面是技能名(看得出是哪一个,不是"技能调了几次")。
62
+ - 最多铺 3 个工具 + 2 个技能,其余收成 `+k`;悬停里有完整清单与最近几条结果。
63
+
64
+ **会话计时**(最右)
46
65
 
47
- ### 面板(点胶囊打开)
66
+ ```
67
+ ⏱ 2h 14m
68
+ ```
69
+
70
+ - **本次会话已运行多久**。口径与 [codex-hud](https://github.com/konnga/codex-hud) 的会话时长一致:`现在 − 会话创建时刻`(含等待与空闲)。格式 `<1m` / `45m` / `2h 14m` / `3d 2h`。
71
+ - 悬停补上这段时间真正在干什么:
72
+
73
+ ```
74
+ 本次会话运行时长 · 创建于 2026-10-14 17:58 · 其中模型 1h 29m、工具 23m · 27 轮 / 380 步
75
+ ```
76
+
77
+ 后两项来自内置 `sessionStats` 投影;那个投影没有时只显示挂钟时长,不编造。
78
+ - 刚重启的头几秒可能还没有它:会话是异步恢复进宿主存储的(实测约 30 秒)。所以取数失败按 **3 秒**重问,拿到后改成 60 秒一次。会话已归档或宿主没有 `sessions` 服务时,整枚不画。
79
+
80
+ 实机效果图:
81
+
82
+ ![悬停会话计时胶囊:上方弹出气泡写着「本次会话运行时长 · 创建于 2026-10-14 17:58 · 其中模型 2h 49m、工具 36m · 47 轮 / 607 步」,下方是胶囊本身「⏱ 4d 16h 31m」](docs/images/pill-tip.webp)
83
+
84
+ *同一套气泡也用在 Git 与工具胶囊上(Git 那颗是多行的:完整路径 / 上游 / 各类型计数)。*
85
+
86
+ ### 面板(点 Git 胶囊打开)
48
87
 
49
88
  ![面板:左边是改动概览与本会话改了哪些、改动清单、最近提交、标签;中间是这次提交的明细;右边是差异](docs/images/panel.webp)
50
89
 
51
- *上图是「看某次提交」时的样子:左边是面板本身,中间是这次提交改了哪个文件,右边是差异。标题栏可拖动,`⟳` 刷新 · `⌖` 复位位置 · `✕` 收起。*
90
+ *上图是「看某次提交」时的样子。标题栏可拖动,`⟳` 刷新 · `⌖` 复位位置 · `✕` 收起。*
52
91
 
53
92
  1. **仓库路径 · 上游 · 短 oid**
54
93
  2. **改动概览** —— 按类型分组的彩色计数;干净时写「工作区干净」。
55
- 3. **本会话改了哪些** —— 一行计数(`本会话改过 3 个文件 · 另有 2 个可能相关 · 1 个已不在 git 现状里`)加开关:`只看本会话改的`、`只看最近一轮`(拿得到回合信息时才出现);有已审标记时还有 `已审 3/8` 与 `清空已审`。
94
+ 3. **本会话改了哪些** —— 一行计数加开关:`只看本会话改的`、`只看最近一轮`;有审阅标记时还有 `已审 3/8` 与 `清空已审`。
56
95
  4. **改动清单** —— 每行 `标记 状态字母 路径`,重命名读作 `旧 → 新`。
57
- - 行首:`●` 确定改过 · `◐` 可能相关(从命令里看出来的,悬停给出那条命令)· `○` 与本会话无关。
58
- - 行尾:`○` / `✓` 是审阅标记 —— 点一下或按 `v` 切换;`✓` 变黄表示改动又变了,需要重看。
96
+ - 行首 `●` 确定改过 · `◐` 可能相关(从命令里看出来,悬停给出那条命令)· `○` 与本会话无关。
97
+ - 行尾 `○` / `✓` 是审阅标记,点一下或按 `v` 切换;`✓` 变黄说明改动又变了,需要重看。
59
98
  - 点任意一行看这个文件的差异。
60
99
  5. **最近提交** —— `短sha 标题 [HEAD] 2026-10-16 14:18`;点一行看这次提交,再点一次收起。
61
- 6. **标签** —— `tag 名 短sha [HEAD] 时间`,新的在前;点一行看它指向的提交。仓库没有标签时会写一行「这个仓库还没有标签」。
100
+ 6. **标签** —— 新的在前;点一行看它指向的提交。没有标签时写一行「这个仓库还没有标签」。
101
+
102
+ 时间一律是**完整年月日 + 时分**(本地时区)。
62
103
 
63
- 时间一律是**完整年月日 + 时分**(本地时区),提交与标签两处一样。
104
+ ### 差异、提交明细与图片
64
105
 
65
- ### 差异与提交明细
106
+ - **看差异**:两栏,工具栏是 `未暂存` / `已暂存` / `自动换行` / `复制差异`;点 hunk 头可折叠那一段。
107
+ - **看提交**:三栏 —— 面板 │ 这次提交 │ 差异,并自动打开这次提交的第一个文件。
108
+ - **两条抓握都能拖**:右边缘那条调差异栏宽度(默认 470px),提交明细栏右边那条调它(默认 240px)。两条宽度都会记住。
109
+ - **看图片改动**:认得出是图片的文件(PNG / JPEG / GIF / WebP / BMP,**按文件头认,不看扩展名**)会画成两张并排,并给出尺寸与字节变化(`1024×768 → 1024×512`、`2.0 KB → 1.0 KB`)。画不出来时说明原因:超过单侧 4 MB、不是可预览的图片、或缺这一侧(新增 / 删除)。
110
+ - **图片缩放**:常显的 `−` / 档位 / `+`,默认「适应宽度」,档位 25% / 50% / 100% / 150% / 200%(按图片固有像素算宽度),点档位本身回到「适应宽度」。档位会记住。
66
111
 
67
- - **看差异**:两栏 —— 左边还是面板,右边是差异。工具栏有 `未暂存` / `已暂存` 页签、`自动换行`、`复制差异`。点 hunk 头可折叠那一段。
68
- - **看提交**:三栏 —— 面板 │ 这次提交 │ 差异,并自动打开这次提交的第一个文件。`Esc` 或 `✕` 收起。
69
- - **两条抓握可以拖**:右边缘那条调差异栏宽度(默认 470px);提交明细栏右边那条调提交明细栏(默认 240px)—— 路径被截断就往左拖。两条宽度都会记住。
70
- - **看图片改动**:二进制文件里认得出是图片时(PNG / JPEG / GIF / WebP / BMP,**按文件头认,不看扩展名**),差异栏画成两张图并排 —— 也可以切成单张来回看 —— 并给出尺寸变化与字节变化(`1024×768 → 1024×512`、`2.0 KB → 1.0 KB`)。两侧各自说明"为什么画不出来":超过单侧 4 MB 预览上限、不是可预览的图片、或缺这一侧(新增 / 删除)。未暂存看「索引 → 工作区」,已暂存看「HEAD → 索引」,提交明细看「父提交 → 这次提交」—— 与文本 diff 的页签语义完全一致。
71
- - **图片缩放**:工具条上是常显的 `−` / 档位 / `+`:默认「适应宽度」,档位走 25% / 50% / 100% / 150% / 200%(200% 封顶),点档位本身回到「适应宽度」。固定档位按**图片固有像素**算宽度(宽高由宿主一并给出,第一帧就算对,不用等图片加载),超出部分由差异栏横向滚动。档位**会记住**(与「自动换行」一样落盘)。<br>内置的右侧文档预览也有缩放,但它的控件是**藏在"预览区底部 72px 的悬停感应带"里的浮层**(CSS 默认 `opacity:0`,指针离开 420ms 收起),滚轮缩放还必须按 Ctrl/⌘ —— 看不见按钮是正常的;这一排按钮就是为了不依赖它。
112
+ ![差异栏里的图片改动:工具栏是未暂存/已暂存/自动换行/复制差异,下面是「并排」与 − 100% + 缩放按钮,橙色高亮写着「尺寸 190×140 → 230×160」和「8.8 KB → 11.4 KB」,两张图左右并排,左标「索引」右标「工作区」](docs/images/image-diff.webp)
72
113
 
73
- ### 轮尾的「本轮图片改动」(在内置改动卡片旁边)
114
+ ### 轮尾的「本轮图片改动」
74
115
 
75
- 内置那张「已编辑 N 个文件」的卡片,点一行是打开本轮的 review tab —— 图片在那里看不见(内置正文对二进制只给一句文案,而且没有给插件留正文槽位)。所以本插件在同一处轮尾放了一条自己的门:
116
+ ![轮尾的「本轮图片改动」:三张缩略图,命令行听来的两张带 ◐ 标记,每张后面跟着一个 ⇄,末尾写「还有 3 个」](docs/images/turn-images.webp)
76
117
 
77
- ![轮尾的「本轮图片改动」:三张缩略图,命令行旁听来的两张带 ◐ 标记,每张后面跟着一个 ⇄,末尾写「还有 3 个」](docs/images/turn-images.webp)
118
+ 内置那张「已编辑 N 个文件」的卡片里看不到图片,所以本插件在同一处轮尾放了自己的门:
78
119
 
79
- - **点缩略图 → 在右侧内置文档预览里打开这张图**(图片原生渲染、可缩放);
80
- - 右边那个 `⇄` → 打开本插件的面板,看这张图的**前后对比**(内置预览只有当前这一版);
81
- - 只列**这一轮**改过的图片(按会话归因里的回合号收窄),最近改的在前,最多 4 张 + `还有 N 个`;这一轮没动过图片时整条不渲染;
82
- - 归因**两档都收**:写文件/编辑工具改的算确定(不标符号),从 shell 命令里认出来的标 `◐`、悬停给出那条命令 —— 图基本是脚本产出的(`python gen.py`、`cp`、`curl -o`),只收确定档等于收不到东西。
120
+ - 点缩略图 → 在右侧内置文档预览里打开这张图;
121
+ - 点 `⇄` → 打开本插件的面板,看这张图的**前后对比**(内置预览只有当前这一版);
122
+ - 只列**这一轮**改过的图片,最近改的在前,最多 4 张 + `还有 N 个`;这一轮没动过图片就整条不渲染;
123
+ - 归因两档都收:工具改的算确定,从 shell 命令里认出来的标 `◐`(悬停给出那条命令)—— 图基本是脚本产出的,只收确定档等于收不到。
83
124
 
84
- ### 侧栏会话行(悬停或点行尾 `⋯`)
125
+ ### 侧栏会话行
85
126
 
86
- 侧栏那一行本身没有标记;信息在按需展开处,都是文字:
127
+ 侧栏那一行本身没有标记,信息在悬停或点行尾 `⋯` 展开处:
87
128
 
88
129
  ```
89
130
  main* ↑0 ↓0 · 已修改 7 未跟踪 2
90
131
  本会话改过 3 个文件 · 命令旁听到 4 个可能改动的路径(1 个现在有差异)
91
132
  ```
92
133
 
93
- 干净时写明「工作区干净」「本会话没有改动记录」。
134
+ 干净时写「工作区干净」「本会话没有改动记录」。
94
135
 
95
- ## 键盘
136
+ ### 键盘
96
137
 
97
- **先在面板里点一下**(或 Tab 进去)才接管按键;点到面板外就交还。Cmd/Ctrl/Alt 组合键与输入框里的按键一律不碰。
138
+ **先在面板里点一下**(或 Tab 进去)才接管按键,点到面板外就交还。Cmd/Ctrl/Alt 组合键与输入框里的按键一律不碰。
98
139
 
99
- | 键 | 作用 |
100
- | --- | --- |
101
- | `↑` `↓` | 上下移动选中行(只移动,不打开) |
102
- | `Enter` | 打开选中的那条 |
103
- | `[` `]` | 上一个 / 下一个文件,并直接打开 |
104
- | `n` `p` | 下一个 / 上一个 hunk(折叠着的会展开) |
105
- | `Space` | 折叠 / 展开当前 hunk |
106
- | `v` | 把当前行标成「这一版我审过了」(再按取消) |
107
- | `r` | 重新读取 |
108
- | `Esc` | 退一层:先收右栏(差异 / 提交明细),再按才收面板 |
140
+ | 键 | 作用 |
141
+ | ------------- | ------------------------------------------------- |
142
+ | `↑` `↓` | 上下移动选中行(只移动,不打开) |
143
+ | `Enter` | 打开选中的那条 |
144
+ | `[` `]` | 上一个 / 下一个文件,并直接打开 |
145
+ | `n` `p` | 下一个 / 上一个 hunk(折叠着的会展开) |
146
+ | `Space` | 折叠 / 展开当前 hunk |
147
+ | `v` | 把当前行标成「这一版我审过了」(再按取消) |
148
+ | `r` | 重新读取 |
149
+ | `Esc` | 退一层:先收右栏(差异 / 提交明细),再按才收面板 |
109
150
 
110
151
  看提交明细时,`↑ ↓ Enter [ ]` 作用于明细那一栏的清单。
111
152
 
112
- ## 它不做什么
153
+ ### 输入框里按 `↑` 召回上一条 prompt
113
154
 
114
- - **只读**:不写 index、不动工作区与 git 配置,不执行 `add` / `commit` / `checkout` / `fetch`;不显示凭证。**读文件内容只有一种情形**:看图片改动时读那两侧的字节 —— 只读、只在内存里、走数据 URL 画出来,不落盘、不外链。
115
- - **归因是两档估计**:经写文件 / 编辑工具的算「确定改过」;从 shell 命令里认出来的算「可能相关」(`>` `>>` `tee`、`sed -i` / `perl -i`、`mv` / `cp` / `rm` / `touch` / `dd of=`、`git checkout|restore <路径>`)。**会漏也会多报**,所以永远标 `◐`,不冒充 `●`;其余命令只记进命令历史,不猜路径。
116
- - **记录不落盘**:会话改动与工具活动都活在宿主进程里,重启归零;每个会话会写明「自 … 起记录」。
117
- - **上限**:改动清单 200 条、单会话归因 500 个文件、标签 100 个、最近提交 10 条 —— 超出只计数并标 `truncated`。
118
- - **图片预览的边界**:只认 PNG / JPEG / GIF / WebP / BMP(按文件头,不认 SVG);单侧超过 4 MB 只报大小不画图;**只在本插件的差异栏里生效** —— DSH 自带的改动对比页(内置 `deliverables` 的 `changes-review` 页签)没有给"文件正文"留槽位,插件改不了那一页。
119
- - **审阅签名用 `size + mtimeMs`**:`touch` 一下(内容没变)也会让「已审」失效 —— 宁可让你多看一眼。
120
- - **计数按文件算**:未跟踪不折叠目录(与编辑器一致);同一个文件「既暂存又改动」算 1 条。
155
+ 输入框为空时按 `↑`,带上一条 prompt;继续按往更早翻,`↓` 往回翻,翻过最新一条就回到你原来的草稿。
121
156
 
122
- ## 存在浏览器里的东西
157
+ - **只处理纯文本**:`/命令`、`@文件` 本来就是文本,照原样带回来仍然有效;附件、图片不会跟着回来。
158
+ - **数据来自会话日志**(内置 `turnOutline` 投影),不是插件自己记一份 —— 重启、分页、压实都不影响,**在别的客户端发过的话也能召回**。宿主的投影没有时,整个功能静默不启用。
159
+ - **输入框非空时完全不接管**,多行草稿里的 `↑` 永远只是移动光标,也不会跟 `/` 命令、`@` 提及的弹窗打架。带修饰键、输入法组合中、有选区时同样让路。
160
+ - 你一打字就退出历史模式,草稿不会被错还原。
123
161
 
124
- | 键 | 内容 |
125
- | --- | --- |
126
- | `dsh-hud.ui.v1` | 面板展开状态、拖动位置、两条拖出来的宽度、开关 |
127
- | `dsh-hud.reviewed.v1` | 「已审」标记(按工作区 + 文件记签名,最多 200 条) |
128
- | `dsh-hud.debug` | 最近 24 行自诊断 —— 排查「界面没反应」用,可随手删 |
162
+ > 实现说明:DSH 的输入框是 Lexical 的 `contenteditable`,插件碰不到它的内部模型,只能模拟一次粘贴(失败退到 `execCommand`、再退到直接改文本),每层都等落地后回读确认。这是全插件唯一贴着 DOM 走的地方,DSH 改结构时它可能失效 —— 失效即静默不启用。
129
163
 
130
164
  ## 开发
131
165
 
132
166
  - `lib/index.js`:宿主半(跑 git、提供 `/dsh-hud-rpc`)。
133
167
  - `lib/client.js`:浏览器半(**无构建步骤**,手写 JS,只依赖种子模块 `react`)。
134
- - `npm test`:全部用例(`node --test test/*.test.mjs`)。
168
+ - `npm test`:全部用例(`node --test test/*.test.mjs`)。零依赖、不用装东西。
135
169
  - `docs/dock-slot-host.md`:把输入框上方那一行做成「可注册行内宿主」的提案,给上游看的。
136
170
  - **发版**:`npm run tag && npm publish`。`prepublishOnly` 先跑测试,再校验「版本号 ↔ git tag」(工作区要干净、`v<版本>` 要存在且指向 HEAD),对不上就发不出去。
137
171
 
Binary file
Binary file
Binary file