@young1lin/dsh-ui-gitworkbench 0.1.11 → 0.1.13
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/AGENTS.md +1 -1
- package/CHANGELOG.md +28 -0
- package/CHANGELOG_EN.md +28 -0
- package/README.md +100 -50
- package/README_EN.md +2 -1
- package/lib/client.js +6902 -6256
- package/package.json +1 -1
- package/src/client/ChangesFileTree.tsx +550 -0
- package/src/client/ChromeGlyph.tsx +27 -0
- package/src/client/CodeEditor.tsx +129 -3
- package/src/client/CommitHistory.tsx +1001 -0
- package/src/client/DiffViews.tsx +1070 -0
- package/src/client/GitWorkbenchPanel.module.css +15 -2513
- package/src/client/GitWorkbenchPanel.tsx +37 -3959
- package/src/client/PaneDivider.tsx +74 -0
- package/src/client/WorkbenchControls.tsx +1047 -0
- package/src/client/WorktreeGlyph.tsx +24 -0
- package/src/client/cm-search-theme.ts +250 -0
- package/src/client/diff-nav.ts +59 -0
- package/src/client/git-workbench-types.ts +252 -0
- package/src/client/locales.ts +14 -8
- package/src/client/row-window.ts +23 -0
- package/src/client/search-count.ts +125 -0
- package/src/client/side-rows.ts +66 -0
- package/src/client/styles/changes.css +505 -0
- package/src/client/styles/controls.css +236 -0
- package/src/client/styles/environment.css +89 -0
- package/src/client/styles/files.css +113 -0
- package/src/client/styles/history-filters.css +400 -0
- package/src/client/styles/history.css +276 -0
- package/src/client/styles/image.css +67 -0
- package/src/client/styles/operations.css +179 -0
- package/src/client/styles/shell.css +431 -0
- package/src/client/styles/themes.css +224 -0
- package/src/client/use-change-nav.ts +6 -5
- package/src/client/use-row-window.ts +55 -0
package/AGENTS.md
CHANGED
|
@@ -74,7 +74,7 @@ are what those freezes cost to find.
|
|
|
74
74
|
|
|
75
75
|
## Testing pattern
|
|
76
76
|
|
|
77
|
-
Pure rules live in React/CSS-free modules so vitest can load them — `src/client/stage-tree.ts`, `diff-model.ts`, `worktree-view.ts`, `commit-graph.ts`, `op-feedback.ts`, `themes.ts`, `highlight.ts` (client); `worktree.ts`, `style-store.ts`, `atomic-json.ts`, `commit-cache.ts`, `git-ops.ts`, `git-log.ts` (host). React state stays in `GitWorkbenchPanel.tsx` (~
|
|
77
|
+
Pure rules live in React/CSS-free modules so vitest can load them — `src/client/stage-tree.ts`, `diff-model.ts`, `worktree-view.ts`, `commit-graph.ts`, `op-feedback.ts`, `themes.ts`, `highlight.ts` (client); `worktree.ts`, `style-store.ts`, `atomic-json.ts`, `commit-cache.ts`, `git-ops.ts`, `git-log.ts` (host). React state orchestration stays in `GitWorkbenchPanel.tsx` (~2000 lines); rendered features live in `ChangesFileTree.tsx`, `CommitHistory.tsx`, `DiffViews.tsx`, and `WorkbenchControls.tsx`, all sharing the root panel CSS Module contract. New behavior = pure helper + unit tests first, component wiring after.
|
|
78
78
|
|
|
79
79
|
`scripts/` holds the live probes — `probe_worktree.py` (host RPCs), `verify_worktree_ui.py` (6-step Playwright UI probe), `llm_smoke.py` (real-LLM smoke). They are local-only and git-ignored: they embed machine-local paths and need a running dsh instance.
|
|
80
80
|
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
本文件记录面向使用者的变更。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循语义化版本。
|
|
4
4
|
|
|
5
|
+
## [0.1.13] - 2026-08-25
|
|
6
|
+
|
|
7
|
+
### 新增
|
|
8
|
+
|
|
9
|
+
- **查找面板会数数了**。Ctrl/Cmd+F 的查找框旁边多了 `3/128`——当前第几个、一共多少个。此前面板不报数,于是「一个都没匹配上」和「匹配全在屏幕外」看起来一模一样。数一遍要走整个文档,所以它不在按键路径上:打字停下来之后才算,用的是语法着色和实时 diff 底色同一个空闲档;走到 5000 个就停,再多显示 `5000+`。命中位置留着不丢,所以按 Enter 在匹配之间跳是一次二分查找而不是重数一遍。拿本仓库自己的客户端源码实测,全量计数 300 行 3–5ms、2000 行 9–11ms、4000 行 12ms、20000 行(`SIDE_LINE_CAP`,窗格能载入的上限)60ms。
|
|
10
|
+
|
|
11
|
+
### 修复
|
|
12
|
+
|
|
13
|
+
- **Ctrl/Cmd+F 的查找面板不再是库自带的那身灰壳**。`@codemirror/search` 给面板的每个值都是写死的字面量:`#f5f5f5` 的条、灰色渐变的按钮、`1px solid silver` 的输入框、`#ffff0054` 的命中底色,外加一个不指定字体族的 `font-size: 70%`。它们一个都不跟调色板走,于是抽屉十四套配色里有十一套下面,Ctrl+F 打开的是一块浅灰色原生表单控件板,压在深色窗格上。现在面板穿的是抽屉自己的控件:同样的高度、圆角、字号、悬停与焦点圈,命中底色也从调色板里取。
|
|
14
|
+
- **行号槽不再把代码压在自己底下**。CodeMirror 用内联样式把行号槽钉成 `position: sticky`,横向滚动时它停在窗格左缘、代码从底下滑过去;库自带一层不透明底色正是为挡住这一幕,而抽屉此前把它改成了透明,于是行号和代码叠印在一起。现在行号槽有自己的底色(取窗格地色),并向左溢出,连窗格左内边距那一条缝也一并盖住。
|
|
15
|
+
|
|
16
|
+
### 变更
|
|
17
|
+
|
|
18
|
+
- **抽屉里同一件事只剩一种画法**。此前七类列表行有四种圆角、两种悬停色、三种「选中」写法,History 的筛选弹层里挤着 20 / 22 / 26px 三种控件高度,紧挨着一排 24px 的控件。现在稠密列表行圆角统一,中性悬停只有一种颜色,「选中」只有一条规则(强调色文字 + 强调色底 + 强调色描边),筛选弹层里的控件全部站到面板内控件的统一高度上。变更树的目录行和文件行此前根本没有圆角,悬停和选中的填充会方角撞上窗格边——现在与 Files 树一致。
|
|
19
|
+
|
|
20
|
+
## [0.1.12] - 2026-08-23
|
|
21
|
+
|
|
22
|
+
### 修复
|
|
23
|
+
|
|
24
|
+
- **全部暂存之后,Staged 页终于有了看得见的退路**。此前取消暂存并非不能做:清掉左侧文件/目录勾选可以整项 Unstage,悬浮 Staged 里的变更块也会出现 Unstage hunk;但两条路都藏在用户必须事先知道的手势里,固定头部又只在编辑模式挂区块按钮,于是「全部 Stage」后的空白 Unstaged 页看起来像不可逆。现在 Staged 头部常驻当前块与 `change current / total`:单块文件直接显示 **Unstage file**,多块文件同时显示 **Unstage hunk / Unstage file**;点击或 F7 / Shift+F7 会切换并完整描边当前块。整文件操作仍走同一条带 `diffSha` 过期保护的 patch 路径,成功后内容回到 Unstaged。
|
|
25
|
+
- **进入 Edit 后不再丢掉 Stage / Revert**。编辑模式保留固定的当前块工具栏与显式块导航;buffer 尚未保存时,Git 区块按钮留在原位但禁用,并说明先保存或放弃编辑,Save / Discard edits 仍然可用。这样按钮不会在最需要确认去向时突然消失,也不会把未保存的编辑和旧 diff 混在一次 Git 操作里。
|
|
26
|
+
- **长 diff 刷新后不再沿用上一份文档的虚拟滚动高度**。窗口状态以 diff identity 为键;切换文件、切换 Staged / Unstaged 或操作后重载时,旧行数不能再把新内容撑出一大片空白。
|
|
27
|
+
- **第一块变更的工具条不再被顶边裁掉**,Stage / Revert / Unstage 在文件第一行开始变化时也完整可点;当前选中块改画一圈连续外框,不再给每一行各画一格蓝色“梯子”。固定操作区在窄窗格里会自动换行,不会把恢复出口挤出可见范围。
|
|
28
|
+
|
|
29
|
+
### 内部
|
|
30
|
+
|
|
31
|
+
- 将约六千行的 `GitWorkbenchPanel.tsx` 按变更树、diff、历史、控制区与图标拆成职责单一的组件;样式按功能拆到 `src/client/styles/*.css`,入口仍由一个 CSS Module 在构建期内联,因此运行时仍只有一张类名表和一个 `<style>`,没有多次加载或额外请求。AST / CSS 结构守卫限制编排文件回涨,并验证固定区块操作与单一样式契约。
|
|
32
|
+
|
|
5
33
|
## [0.1.11] - 2026-08-21
|
|
6
34
|
|
|
7
35
|
### 修复
|
package/CHANGELOG_EN.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
User-facing changes, newest first. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows SemVer.
|
|
4
4
|
|
|
5
|
+
## [0.1.13] - 2026-08-25
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **The find panel counts.** Ctrl/Cmd+F now shows `3/128` beside the search field — which match you are on, and how many there are. Without it, a query that matched nothing and a query whose matches are all below the fold looked identical. Counting walks the whole document, so it never happens on the keystroke path: the walk waits until the typing stops, on the same idle the syntax coloring and the live diff tint use, and it stops at 5,000 matches, past which the total reads `5000+`. Match positions are kept, so moving between matches with Enter is a binary search rather than a second walk. Measured against this repository's own client sources, a full count costs 3–5ms at 300 lines, 9–11ms at 2,000, 12ms at 4,000, and 60ms at 20,000 — `SIDE_LINE_CAP`, the ceiling the pane will load.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **The Ctrl/Cmd+F panel no longer arrives in the library's grey shell.** Every value `@codemirror/search` dresses its panel with is a literal: a `#f5f5f5` strip, buttons on a grey gradient, `1px solid silver` fields, `#ffff0054` matches, and a `font-size: 70%` that names no font family. None of them follow a palette, so on eleven of the drawer's fourteen themes Ctrl+F opened a light-grey slab of native form controls on top of a dark pane. The panel now wears the drawer's own controls — the same height, radius, type size, hover and focus ring — and takes its match colors from the palette.
|
|
14
|
+
- **The line-number gutter no longer prints the code through itself.** CodeMirror pins the gutter with an inline `position: sticky`, so the numbers hold the pane's left edge while the code scrolls sideways underneath them; the library ships an opaque fill there for exactly that reason, and the drawer had overridden it to transparent, leaving numbers and code painted on top of each other. The gutter now carries the pane's ground color, and bleeds left far enough to cover the pane's own left padding.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **One way to draw each thing.** Seven kinds of list row had four answers for a corner, two hover colors and three spellings of "this one is selected", and the History filter popover held controls at 20 / 22 / 26px next to a row of controls at 24. Dense list rows now share one radius, neutral hovers share one color, selection is one rule (accent text in an accent tint inside an accent border), and every control in the filter popover stands at the standard in-pane height. The Changes tree's directory and file rows had no corner at all, so their hover and selection fills ran square into the pane edge — they now match the Files tree.
|
|
19
|
+
|
|
20
|
+
## [0.1.12] - 2026-08-23
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- **The Staged pane now leaves an obvious way back after everything is staged.** Unstaging was technically possible before: clearing a file or directory tick unstaged that selection, and hovering a staged hunk revealed Unstage hunk. Both routes depended on a gesture the user already had to know, while the fixed header mounted hunk actions only in Edit mode, so an empty Unstaged pane looked irreversible. The Staged header now keeps the current hunk and `change current / total` visible: a one-hunk file shows **Unstage file**, while a multi-hunk file shows both **Unstage hunk / Unstage file**. Clicking a hunk or pressing F7 / Shift+F7 selects it and draws one continuous outline. Whole-file unstage uses the same stale-`diffSha`-checked patch path and returns the content to Unstaged.
|
|
25
|
+
- **Entering Edit no longer removes Stage / Revert.** Edit mode keeps a fixed current-hunk toolbar and explicit hunk navigation. An unsaved buffer leaves Git hunk actions in place but disabled with an explanation, while Save / Discard edits remain available. This prevents both a disappearing escape route and applying an old diff selection to unsaved text.
|
|
26
|
+
- **Refreshing a long diff no longer reuses the previous document's virtual scroll height.** Window state is keyed by diff identity, so switching files or layers and reloading after an operation cannot leave the new content padded to stale row counts.
|
|
27
|
+
- **The first change block's action bar is no longer clipped by the top edge**, including files that change from line one. The selected hunk now draws one continuous perimeter instead of a blue box around every row, and fixed actions wrap in narrow panes rather than pushing recovery controls out of view.
|
|
28
|
+
|
|
29
|
+
### Internal
|
|
30
|
+
|
|
31
|
+
- Split the roughly 6,000-line `GitWorkbenchPanel.tsx` into focused change-tree, diff, history, controls, and glyph modules. Styles now live by feature under `src/client/styles/*.css`, still inlined through one CSS Module at build time, so runtime keeps one class map and one `<style>` element with no extra requests. AST and CSS structure guards cap orchestrator regrowth and protect the fixed-hunk-action and single-style contracts.
|
|
32
|
+
|
|
5
33
|
## [0.1.11] - 2026-08-21
|
|
6
34
|
|
|
7
35
|
### Fixed
|
package/README.md
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
每个会话的头部都有一枚状态卡,显示当前分支、领先/落后和增删计数。点开它,右侧滑出一张工作台面板,当前 worktree 的改动一览无余:
|
|
8
8
|
|
|
9
|
-
-
|
|
9
|
+
- **变更**:可折叠的文件树,配完整上下文的左右并排 diff——双列行号、词级高亮、Shiki 语法着色,右栏可直接 Edit;树顶可打关键字过滤文件列表(多词与关系、智能大小写),文件行悬浮可一键撤回到上次提交(IDEA 的 Rollback,弹窗先说清后果);diff 头部常驻当前变更块与 `current / total`,Unstaged 可 Stage / Revert(进入 Edit 也保留),Staged 可 Unstage 当前块或整个文件;
|
|
10
|
+
- **文件**:仓库目录树与可编辑文件查看器,支持搜索、图片预览、CodeMirror 编辑和 blame 行信息;
|
|
10
11
|
- **历史**:提交列表 / 文件树 / diff 三栏并排,滚动到底自动翻页;行内带作者、悬浮卡带精确时间;IDEA 式过滤(`user:` / `path:` / `after:` 输入语法,或作者 / 日期 / 路径分区漏斗弹层),条件编译进 `git log`、全历史匹配、车道图常驻,另有「全部分支」;
|
|
11
12
|
- **对比**:任选两个分支互相比较;
|
|
12
13
|
- **提交与同步**:树上勾选文件就是真实的 `git add` / `git restore --staged`,配合提交框和 fetch / pull / push 同步条,一次提交加推送全程不用离开面板;
|
|
@@ -88,9 +89,13 @@ irm https://raw.githubusercontent.com/young1lin/dsh-ui-gitworkbench/main/scripts
|
|
|
88
89
|
| 状态卡绑定标记(树形图标;徽标文字与分支重名时省略)+ 头部 worktree 选择器 | ✅ | `python scripts/verify_worktree_ui.py`:6 步 UI 探针(绑定标记、头部路径、选择器切换、折叠/选中回归) |
|
|
89
90
|
| 历史过滤(作者 / 日期 / 路径下推 `git log`、「全部分支」、日历与三态路径树) | ✅ | `python scripts/verify_history_feature.py`:11 步 UI + host 探针全过(中文作者、All-branches、日历选界、目录吸收文件勾选、诚实空态) |
|
|
90
91
|
| 单文件撤回(Rollback)与文件列表关键字过滤 | ✅ | 对 live app 实测:撤回弹窗措辞随 host 实时推导的后果变化、取消不动手、执行后 fixture 回静息态;过滤框多词 AND、忽略折叠、根勾选只动可见行 |
|
|
92
|
+
| 变更块导航与 Staged 恢复出口 | ✅ | `tests/edit-hunk-actions.test.ts` + scratch fixture live probe:Staged 常驻 Unstage file,多块另有 Unstage hunk;操作后回到 Unstaged,页面无错误 |
|
|
91
93
|
| 客户端半被类型检查 | ✅ | `tsconfig.client.json` 进了 `bundle`/`typecheck`;曾故意写坏一处,确认报 `TS2322` |
|
|
92
94
|
| 主题 7 族 × 亮暗 + 跟随系统明暗 | ✅ | `tests/theme-palettes.test.ts` 把 `themes.ts` 与 `.module.css` 互扣(两个方向都验过会红);`lib/client.js` 含全部 14 套调色板 |
|
|
93
95
|
| 背景图 / 自定义 CSS 的项目+全局存储 | ✅ | 对**构建产物** `lib/index.js` 跑 styleGet/styleSet 全流程(临时 HOME,18/18 PASS):读写、项目优先、越界钳制、恶意 image 拒绝、清空删记录、非仓库拒绝、两作用域并发写不互相覆盖 |
|
|
96
|
+
| Ctrl/Cmd+F 查找面板穿抽屉的控件,并报 `当前 / 总数` | ✅ | `python scripts/verify_search_panel.py`:24 项实机检查(条随调色板重绘、控件同高同圆角、命中底色非库自带、窄窗格回流、计数随 Enter 前进) |
|
|
97
|
+
| 抽屉视觉词汇表单一(圆角 / 字号 / 控件高度 / 悬停 / 选中) | ✅ | `tests/drawer-chrome.test.ts` 逐条声明扫描全表,六个变异全红;`python scripts/verify_vocabulary.py` 实机复核(18 个筛选控件同高、17 处小字同号、树行圆角与选中 chip) |
|
|
98
|
+
| 行号槽不再把代码压在底下 | ✅ | `python scripts/verify_gutter.py`:窗格拖窄后横向滚动 400px,63 行钻到槽下,槽有自身底色且向左溢出;可编辑轨条仍在槽之上 |
|
|
94
99
|
|
|
95
100
|
**已知边界**:状态卡挂在 `conversation.session.header.actions` 插槽,只有**打开了会话(会话头渲染)**时才挂载。无头自动化里若没真正打开会话,状态卡不会出现——这是预期行为,手动在 UI 里开一个会话即可看到。
|
|
96
101
|
|
|
@@ -139,11 +144,13 @@ export function apply(ctx) {
|
|
|
139
144
|
- **拿 worktree 路径**:`useSessions(state => state.byId[sessionId]?.cwd)`——会话摘要自带 `cwd`。
|
|
140
145
|
- **数据刷新**:挂载时拉一次 + 面板打开时轮询(空闲 15s、agent 运行中加密到 3s——运行中的会话正在改文件,等满 15s 看到的就是旧闻)+ 手动刷新按钮。**面板关着时另有一条便宜的绑定探针**(见 §6.0d):只在 agent 运行中开表,走不 spawn git 的 `sessionWorktree`,发现绑定变了才补一次 `worktreeStatus`。
|
|
141
146
|
|
|
142
|
-
### 2.3 组件与样式(`
|
|
147
|
+
### 2.3 组件与样式(`GitWorkbenchPanel.tsx` + 功能组件 + `styles/*.css`)
|
|
143
148
|
|
|
144
149
|
- **外壳**:面板是一张四边留白的卡片(`--gs-inset`,14px 圆角、投影),最大化按钮切到满屏。**三条边可拖**:卡片左缘(`MIN_DRAWER_WIDTH`)、提交列表与文件树之间、文件树与 diff 之间。三处共用 `useHorizontalDrag`(pointer capture + `pointercancel`)。窗格上界由 `applyPane` 现场量出来算:`面板宽 - 邻窗格宽 - MIN_DIFF_WIDTH`,diff 是唯一不能折行的窗格,所以它的下限是硬的。宽度与主题存 localStorage。
|
|
145
150
|
- **布局**:变更页 = **文件树 + 逐文件 diff** 两栏;历史页 = **提交列表 + 文件树 + diff** 三栏并列(GitHub Desktop / JetBrains git log 的做法),各自独立滚动,因此没有可折叠的东西要解释。翻页是滚动哨兵(IntersectionObserver),不是按钮。
|
|
151
|
+
- **逐块操作**:`DiffViews.tsx` 用完整上下文 side rows 把连续增删行归成块;点击代码块或按 F7 / Shift+F7 更新显式 current block,头部固定按钮始终作用于这一个块。Unstaged 提供 Stage / Revert,Staged 提供 Unstage hunk / file;整文件 Unstage 在点击时才收集所有变化行,并沿用 `diffSha` 过期检查。Edit 模式改用 working-tree 真实行号计算 CodeMirror 的 dense 滚动位置,dirty buffer 只禁用 Git 区块操作,不隐藏按钮。
|
|
146
152
|
- diff 渲染:`renderDiff(segment)` 把统一 diff 逐行分类,渲染成 `[老行号][新行号][+/-槽][代码]` 的 flex 行;行号从 `@@ -a,b +c,d @@` 解析并随行递增。
|
|
153
|
+
- **样式装载**:`GitWorkbenchPanel.module.css` 只是一张清单,按功能 `@import` `styles/*.css`;构建在 CSS Modules 作用域化之前内联它们,运行时仍是一张类名表和一个 `<style>`,不是十次网络或十个 style 标签。
|
|
147
154
|
- **配色**:面板自带调色板,不走 dsh 主题 token——diff 需要 增/删/词级/语法 四组颜色,dsh 没有定义。**所有颜色都过 `--gs-*` token**,字面色只出现在 `.overlay[data-gs-theme='<family>-<mode>']` 的调色板块里;换主题=换一组 token,别的什么都不动。**只有状态卡(在 dsh 原生 chrome 里)保留 `--dsw-*` token**。
|
|
148
155
|
- 主题族与解析逻辑在 `src/client/themes.ts`(不 import CSS/React,因此可被测试直接加载):GitHub / IntelliJ IDEA / VS Code / One / Solarized / Nord / Cyberpunk,各带亮暗两套。
|
|
149
156
|
- 明暗默认 `system` = 跟随操作系统(`matchMedia('(prefers-color-scheme: dark)')`,挂载期间持续跟随);显式选亮/暗则完全覆盖。
|
|
@@ -191,55 +198,51 @@ export function apply(ctx) {
|
|
|
191
198
|
|
|
192
199
|
```
|
|
193
200
|
harness-worktree/
|
|
194
|
-
package.json dsh.client(web)
|
|
195
|
-
.npmrc auto-install-peers=false(关键!见 §6.5)
|
|
196
|
-
tsconfig.json tsc
|
|
197
|
-
tsconfig.client.json 仅类型检查【客户端半】(
|
|
198
|
-
tsdown.config.ts
|
|
199
|
-
vitest.config.ts 排除 .agents
|
|
201
|
+
package.json dsh.client(web) + exports + 显式兼容范围的 optional peer(运行时由 profile 提供)
|
|
202
|
+
.npmrc auto-install-peers=false(关键!见 §6.5 / §6.14)
|
|
203
|
+
tsconfig.json tsc 构建【宿主半】(stage-3 装饰器 + ambient shim)
|
|
204
|
+
tsconfig.client.json 仅类型检查【客户端半】(rolldown 本身不做类型检查)
|
|
205
|
+
tsdown.config.ts 客户端 closure-factory bundle + CSS Modules 构建
|
|
206
|
+
vitest.config.ts 排除 .agents/**,避免 worktree 副本重复收集测试
|
|
200
207
|
src/
|
|
201
|
-
index.ts
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
208
|
+
index.ts GitWorkbenchService + 27 个 @Remote + worktree 三个 agent 工具
|
|
209
|
+
stats/fileDiff/fileSides/applyBlocks/writeChecked/blame/fileImage/commitStats/
|
|
210
|
+
commits/authors/repoTree/compareRefs/sessionWorktree/worktreeEnter/worktreeExit/
|
|
211
|
+
worktreeStatus/styleGet/styleSet/syncStatus/stage/unstage/discardPlan/discardFile/
|
|
212
|
+
commit/fetch/pull/push
|
|
213
|
+
atomic-json.ts 崩溃安全 JSON 写入(tmp+rename + Windows EPERM 退避)
|
|
214
|
+
apply-blocks.ts hunk patch 选择、正反向 apply 与 stale diff 防线
|
|
215
|
+
blame.ts porcelain blame 解析与路径/提交信息
|
|
216
|
+
commit-cache.ts commit hash 内容寻址 LRU
|
|
217
|
+
discard-ops.ts IDEA Rollback 的计划推导与路径防线
|
|
218
|
+
fs-remove.ts 受工作区边界保护的文件删除
|
|
219
|
+
git-log.ts/log-filter.ts/shortlog.ts 历史解析、过滤参数与作者名单
|
|
220
|
+
git-ops.ts 写操作 argv + stderr 归类(纯函数,不 spawn)
|
|
221
|
+
image-sniff.ts 图片类型嗅探与读取上限
|
|
222
|
+
patch-model.ts Git patch 解析、行选择与重发射
|
|
223
|
+
side-guard.ts side diff / write 的路径与 stale-sha 校验
|
|
224
|
+
style-store.ts 项目/全局外观存储
|
|
225
|
+
worktree.ts worktree 绑定、名称/分支/porcelain 纯逻辑
|
|
226
|
+
write-checked.ts 编辑保存的编码、mtime/hash 与原子写校验
|
|
227
|
+
types/*.d.ts 宿主/客户端 ambient shim
|
|
213
228
|
client/
|
|
214
|
-
index.ts
|
|
215
|
-
GitWorkbenchPanel.tsx
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
locales.ts zh / en 两份词典
|
|
232
|
-
tests/ vitest:worktree-bindings(存储/原子写/重试)、worktree-derive(名称/分支/porcelain)、ref-name、git-ops(argv/归类)、git-log、commit-cache、style-store、style-resolve、theme-palettes(族×调色板互扣)、stage-tree(勾选模型)、worktree-view、commit-graph、diff-regression(diff 模型/词级区间/Shiki/CSS 不变量)、drawer-chrome(状态卡与面板的结构性扫描)、op-feedback、status-parse(porcelain/numstat 解析、二进制嗅探、截断与上限——fixture 场景目录 TESTS.md 的单测化)、log-filter(条件编译/裸日期展开)、log-filter-query(输入语法/chips)、shortlog、dir-tree、path-select(三态勾选)、calendar、commit-filter(精确时间渲染)、active-file(默认选中排序)、file-filter(关键字过滤)、discard-ops(撤回计划推导 + 危险拼法扫描)
|
|
233
|
-
scripts/
|
|
234
|
-
probe_worktree.py 宿主 RPC 探针:scratch 仓库全流程 + 真仓库冒烟 + 再进入分支复用
|
|
235
|
-
verify_worktree_ui.py UI 探针:状态卡标记/头部路径/选择器切换/折叠回归 6 步(经真实页面 RPC 回放)
|
|
236
|
-
llm_smoke.py 真实 LLM 冒烟:让模型在会话里调 worktree_enter/exit,看目录出现/消失
|
|
237
|
-
verify_turn_refresh.py UI 探针:抽屉关着时回合结束自动刷新状态卡(0.1.2 的刷新链路)
|
|
238
|
-
verify_history_feature.py UI+host 探针:历史过滤两半(条件下推 + 输入框/漏斗/诚实空态)11 步
|
|
239
|
-
(五个 .py 探针为本地集成脚本:需连真实 dsh 实例与 scratch 仓库,内嵌本机路径——已 gitignore,不入库、不随包发布)
|
|
240
|
-
cordis.patch.yml 一行 insert,把宿主 entry 挂进 web profile
|
|
241
|
-
README.md 本文件
|
|
242
|
-
README_EN.md 英文版(面向使用者与维护者;深度细节仍以本文为准)
|
|
229
|
+
index.ts 注册会话头插槽并桥接 RPC 回调
|
|
230
|
+
GitWorkbenchPanel.tsx 状态卡与抽屉的状态编排;业务视图下沉到叶组件
|
|
231
|
+
ChangesFileTree.tsx 变更树、过滤、勾选与提交区
|
|
232
|
+
CommitHistory.tsx 历史列表、车道图、筛选与分页
|
|
233
|
+
DiffViews.tsx unified/side diff、块操作、虚拟窗口与编辑态
|
|
234
|
+
WorkbenchControls.tsx 同步条、设置、来源选择器与反馈
|
|
235
|
+
FileBrowser.tsx/CodeEditor.tsx/ImageView.tsx 文件页、编辑器与图片预览
|
|
236
|
+
PaneDivider.tsx + *Glyph.tsx 拖拽分隔条与共享图标
|
|
237
|
+
git-workbench-types.ts 面板组件/RPC 共享类型
|
|
238
|
+
row-window.ts/use-row-window.ts 视口窗口纯规则与 React 桥接
|
|
239
|
+
styles/*.css 按功能分片;由 GitWorkbenchPanel.module.css 构建期汇成一个 style
|
|
240
|
+
*.ts 勾选、diff、导航、缓存、过滤、主题等 React/CSS-free 纯规则
|
|
241
|
+
tests/*.test.ts 单元、结构扫描、性能边界、泄漏与回归守卫(按领域与源模块对应)
|
|
242
|
+
scripts/*.py 本地 live/UI/性能探针与辅助器(需真实 dsh/scratch;gitignore,不随包发布)
|
|
243
|
+
cordis.patch.yml 宿主 entry 的 profile 挂载声明
|
|
244
|
+
README.md / README_EN.md 中文深度交接文档 / 英文使用与维护说明
|
|
245
|
+
CHANGELOG.md / CHANGELOG_EN.md 双语发布记录
|
|
243
246
|
```
|
|
244
247
|
|
|
245
248
|
---
|
|
@@ -274,7 +277,7 @@ dsh plugin --profile web add <仓库根目录>
|
|
|
274
277
|
# `dsh plugin add` 自动带上补丁,--patch 仅在 profile 于该声明存在之前加入时需要)
|
|
275
278
|
dsh web --patch <仓库根目录>/cordis.patch.yml
|
|
276
279
|
|
|
277
|
-
# 便携交付:tarball 自足——prepack 现场构建 lib
|
|
280
|
+
# 便携交付:tarball 自足——prepack 现场构建 lib/;白名单带 lib/src、安装脚本、双语文档、AGENTS、LICENSE 与补丁
|
|
278
281
|
npm pack
|
|
279
282
|
dsh plugin --profile web add <tgz 路径>
|
|
280
283
|
```
|
|
@@ -381,6 +384,53 @@ git 靠「一删除 + 一新增」的配对才认得出改名;pathspec 只放
|
|
|
381
384
|
### 6.17 抽屉内新增模态层的 CSS 必须写 `.drawer > .xxx`,裸类会被压住
|
|
382
385
|
`.drawer > *:not(.resizer) { position: relative; z-index: 1 }`(布局需要)给了每个直接子元素 position 与层叠秩,裸类声明的 `position: absolute` 会输给它——遮罩被当作最后一个 flex 项排进抽屉底部的一条缝里,样式全对、位置全错、还不报错。模态遮罩一律写成 `.drawer > .confirmScrim` 这种带父作用域的选择器;`tests/drawer-chrome.test.ts` 有断言守着这条作用域与层叠秩。
|
|
383
386
|
|
|
387
|
+
### 6.18 CodeMirror 自带的界面只能在 `EditorView.theme` 里改,且查找面板不能用 flex 排版
|
|
388
|
+
`.cm-*` 是全局类名,写进 `.module.css` 会被 CSS Modules 哈希掉,选不中;改动一律走 TS 里的 `EditorView.theme`(`paneTheme` 与 `cm-search-theme.ts`)。这样写仍然吃得到调色板:面板挂在 `.overlay` 里,`var(--gs-*)` 照常解析。层叠也不用操心——`EditorView` 把 base theme 排在最前面挂载,同特异度下普通 theme 规则赢。
|
|
389
|
+
|
|
390
|
+
排版有个坑:`@codemirror/search` 用一个 `<br>` 分隔「查找行」和「替换行」,而 Blink **不给 flex 容器里的 `<br>` 生成盒子**——`flex-basis: 100%`、`width: 100%`、`min-width: 100%` 三种写法都在跑起来的应用上试过,替换框一律留在查找行上,样式全对、只是少了一次换行。面板因此保持行内流:控件写成 `inline-flex` 原子,行距用每个控件的下外边距承担,面板下内边距按这个边距扣掉;`scripts/verify_search_panel.py` 在真实抽屉里量这套版式。库自带的那套值全是字面量(`#f5f5f5` 的条、`linear-gradient` 的按钮、`1px solid silver` 的输入框、`#ffff0054` 的命中、外加一个不指定字体族的 `font-size: 70%`),一个都不跟主题走,必须逐条盖掉;`tests/cm-search-theme.test.ts` 按名字守着这份清单。
|
|
391
|
+
|
|
392
|
+
### 6.19 探针按类名选元素要用「后缀匹配」,读状态前要先把鼠标挪开
|
|
393
|
+
|
|
394
|
+
CSS Modules 的类名带每次构建都变的哈希前缀(`T3TXCq_file`),所以 Playwright 里
|
|
395
|
+
只能按局部名匹配。但 `[class*="file"]` 太松:它同时选中 `fileLi`、`filePath`、
|
|
396
|
+
`fileStatus`、`fileCountAdd`,第一版 `verify_vocabulary.py` 因此量到了外层
|
|
397
|
+
`<li>`,报告「树行没有圆角」——而圆角就在里面那个 `<button>` 上。按后缀判断才准:
|
|
398
|
+
|
|
399
|
+
```js
|
|
400
|
+
const local = (name) => [...document.querySelectorAll('[class]')]
|
|
401
|
+
.filter(el => [...el.classList].some(c => c === name || c.endsWith('_' + name)));
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
第二个坑在特异度上:`.file:hover` 是 (0,2,0),裸修饰符 `.fileActive` 只有
|
|
405
|
+
(0,1,0),悬停规则必然赢。Playwright 点完一行,指针就停在那行上,`getComputedStyle`
|
|
406
|
+
读回来的是**悬停态**,于是选中态的强调色底会被读成中性的 `--gs-raise`。读状态前
|
|
407
|
+
先 `page.mouse.move(4, 4)`。抽屉里所有选中行都是这个行为:指针压上去时底色让位给
|
|
408
|
+
悬停,强调色文字、600 字重和左侧强调边仍在,选中依然读得出来。
|
|
409
|
+
|
|
410
|
+
还有一条:规则写在子元素上时要读子元素。`.calWeek` 的 11px 写在 `.calWeek span`
|
|
411
|
+
上,读容器拿到的是从面板继承来的 12px,看起来像漂移。
|
|
412
|
+
|
|
413
|
+
### 6.20 行号槽是内联 `position: sticky`,把它改成透明就等于让代码从行号底下穿过去
|
|
414
|
+
|
|
415
|
+
`@codemirror/view` 在 gutter 插件里用**内联样式**写死 `this.dom.style.position =
|
|
416
|
+
"sticky"`(`dist/index.js` 约 11398 行),CSS 覆盖不掉。于是横向滚动时行号钉在面板
|
|
417
|
+
左缘不动,代码从底下滑过去——库自带 `background: #f5f5f5` 正是为了挡住这一幕,
|
|
418
|
+
`paneTheme` 早先把它改成了 `transparent`,行号和代码就叠印在一起了(在跑起来的
|
|
419
|
+
应用上拍到过:`pl0ügin`、`ull5neutral`、`cro3ssed`)。所以 gutter 必须有自己的底色,
|
|
420
|
+
用面板的地色 `--gs-surface`——Files 的 `.fbMain` 和 Changes 的 `.diffPane` 都是它。
|
|
421
|
+
自己上色的格子(活动行、改动行)照旧盖在上面,跟盖在透明上没有区别。
|
|
422
|
+
|
|
423
|
+
只补底色还差一截:`left: 0` 把 gutter 钉在滚动容器的**内容盒**边缘,而面板是在
|
|
424
|
+
**内边距盒**上裁剪的,所以代码会继续从面板那 8px 左内边距里钻出来,露在行号左边。
|
|
425
|
+
底色因此要向左溢出:`boxShadow: '-16px 0 0 0 var(--gs-surface)'`。颜色就是地色、
|
|
426
|
+
又被面板裁掉,多溢一点不要钱。
|
|
427
|
+
|
|
428
|
+
两个连带项。一是 `.cmHost[data-editable]::before` 那条可编辑轨条压着 gutter 头两个
|
|
429
|
+
像素,而 CodeMirror 把 gutter 叠在 `z-index: 200`——轨条得写 `z-index: 201`,否则
|
|
430
|
+
gutter 一变不透明就把它埋了。二是探针查不了这件事:`elementFromPoint` 不做
|
|
431
|
+
box-shadow 的命中测试,行号左边那个点照样报 `.cm-line`,只能截图看像素,或者直接
|
|
432
|
+
读 `getComputedStyle(...).boxShadow`。`scripts/verify_gutter.py` 走的是后者。
|
|
433
|
+
|
|
384
434
|
---
|
|
385
435
|
|
|
386
436
|
## 7. dsh 仓库里的关键参考文件(去哪里抄)
|
package/README_EN.md
CHANGED
|
@@ -6,7 +6,8 @@ An out-of-tree Web UI plugin for [dsh (DeepSeek Harness)](https://github.com/dee
|
|
|
6
6
|
|
|
7
7
|
Every session header gets a small status card showing the current branch, ahead/behind counts, and added/deleted lines. Click it and a workbench panel slides in from the right with everything about the session worktree's changes:
|
|
8
8
|
|
|
9
|
-
- **Changes** — a collapsible file tree beside per-file diffs
|
|
9
|
+
- **Changes** — a collapsible file tree beside full-context, side-by-side per-file diffs with dual line numbers, word-level highlights, Shiki syntax coloring, and an editable right column. A magnifier filters the tree by space-separated keywords (smart case); hovering a file reveals IDEA-style Rollback behind a consequence-specific dialog. The diff header keeps the current hunk and `current / total` visible: Unstaged offers Stage / Revert even in Edit mode, while Staged offers Unstage for the current hunk or the whole file.
|
|
10
|
+
- **Files** — a searchable repository tree with editable CodeMirror file views, image previews, and per-line blame information. Ctrl/Cmd+F opens a find panel dressed in the drawer's own controls that reports `3/128` — which match you are on, out of how many.
|
|
10
11
|
- **History** — commits, file tree, and diff in three panes; scrolling to the bottom loads the next page automatically. Rows carry the author, the hover card the exact time; an IDEA-style filter (a `user:` / `path:` / `after:` query grammar plus an authors / date / paths funnel) compiles into `git log` arguments and matches over all history, with an All-branches option.
|
|
11
12
|
- **Compare** — diff any two branches against each other.
|
|
12
13
|
- **Commit & sync** — ticking a file in the tree is a real `git add` / `git restore --staged`; with the commit box and the fetch / pull / push bar, a full commit-and-push never leaves the panel.
|