@young1lin/dsh-ui-gitworkbench 0.1.2 → 0.1.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/AGENTS.md +1 -1
- package/CHANGELOG.md +45 -0
- package/CHANGELOG_EN.md +45 -0
- package/README.md +39 -6
- package/README_EN.md +3 -2
- package/lib/client.js +2058 -305
- package/lib/discard-ops.js +158 -0
- package/lib/git-log.js +10 -6
- package/lib/git-ops.js +30 -9
- package/lib/index.js +215 -7
- package/lib/log-filter.js +71 -0
- package/lib/shortlog.js +40 -0
- package/package.json +6 -6
- package/src/client/GitWorkbenchPanel.module.css +523 -6
- package/src/client/GitWorkbenchPanel.tsx +1024 -26
- package/src/client/active-file.ts +83 -0
- package/src/client/calendar.ts +99 -0
- package/src/client/commit-filter.ts +49 -0
- package/src/client/dir-tree.ts +112 -0
- package/src/client/file-filter.ts +66 -0
- package/src/client/index.ts +44 -5
- package/src/client/locales.ts +94 -0
- package/src/client/log-filter-query.ts +189 -0
- package/src/client/path-select.ts +131 -0
- package/src/discard-ops.ts +197 -0
- package/src/git-log.ts +24 -6
- package/src/git-ops.ts +39 -7
- package/src/index.ts +215 -6
- package/src/log-filter.ts +87 -0
- package/src/shortlog.ts +46 -0
package/AGENTS.md
CHANGED
|
@@ -46,7 +46,7 @@ Pure rules live in React/CSS-free modules so vitest can load them — `src/clien
|
|
|
46
46
|
- **A tick IS a git call.** Never drive ticks against a worktree someone is looking at. Use the scratch worktree `../gitworkbench-fixture/.agents/worktrees/fixture-01` (6 changed, 0 staged at rest; select-all then deselect-all returns it to 0). The drawer's source pin is per-browser, so a headless client can switch sources without moving the operator's view.
|
|
47
47
|
- **Source-scanning tests have twice been fooled by prose in comments.** Strip comments before scanning, and mutation-test any such guard (change the guarded code, confirm the test goes red).
|
|
48
48
|
- **UI copy is bilingual** (`src/client/locales.ts`, zh + en — add both keys); code comments and commit messages are English.
|
|
49
|
-
- **Commits:** conventional prefix, lowercase subject, a body explaining *why*, ending with `Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com
|
|
49
|
+
- **Commits:** conventional prefix, lowercase subject, a body explaining *why*, ending with a `Co-Authored-By:` trailer per model that worked on the change, ranked by token usage — credit the model(s) that actually wrote it, never a fixed name (history shows the spellings: `Claude Opus 5 (1M context) <noreply@anthropic.com>`, `GLM-5.3 <noreply@zhipuai.cn>`, `Grok-4.6 <noreply@x.ai>`). Remote is `origin` = github.com/young1lin/dsh-ui-gitworkbench; publishing is tag-driven — push `vX.Y.Z` and `.github/workflows/publish.yml` publishes to npm via Trusted Publishing (no local npm login; the workflow re-runs typecheck/tests/build itself).
|
|
50
50
|
- **Other agents may have uncommitted work in this tree** (e.g. `scripts/verify_worktree_ui.py`). Check `git status` first and commit with `git commit --only <paths>` — never sweep the tree, and don't touch files that aren't yours.
|
|
51
51
|
- `.npmrc` must keep `auto-install-peers=false` (dev-time weight control: the harness peers resolve from the web profile / linked checkout; letting pnpm auto-install the whole `@deepseek-ai/*` tree locally adds nothing). The peers ARE published on npm — consumer installs resolve them fine. `@deepseek-ai/*` imports in client code must be `import type` only — the bundle purity gate rejects value imports.
|
|
52
52
|
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
本文件记录面向使用者的变更。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循语义化版本。
|
|
4
4
|
|
|
5
|
+
## [0.1.4] - 2026-08-18
|
|
6
|
+
|
|
7
|
+
### 新增
|
|
8
|
+
|
|
9
|
+
- **提交历史:作者与精确时间**。历史行的缩写 hash 旁直接显示作者;悬浮详情卡新增作者、提交者(仅当与作者不同,如 rebase / cherry-pick / 维护者代提交)、**精确提交时间**(`%cI` 原始时刻,按浏览器本地时区渲染,不再只有 "xx weeks ago")。
|
|
10
|
+
- **IDEA 式下推历史过滤**:条件直接编译进 `git log` 参数(`--author` / `--grep` / `--since` / `--until` / pathspec),在**全部历史**上匹配后再分页——不是只筛屏幕上已加载的页,后面的提交输入条件一样现身。过滤后的页仍是单次连续游走,**车道图常驻**。匹配恒定忽略大小写;字面量自动转义(`a.b` 只匹配 `a.b`),文本条件可选正则。
|
|
11
|
+
- **输入框语法**:`user:名字`(可多个,OR)、`path:路径`、`after:日期` / `before:日期`(吃 git 自然语言日期,如 `2 weeks ago`)、裸词搜提交说明;识别的条件渲染为**可删除的 chips**,一键「清除全部」,引号可包含空格的值。
|
|
12
|
+
- **「筛选条件」漏斗弹层,分区页签**(用户 N / 日期 • / 路径 N,高度恒定,各区激活条件数标在页签上):
|
|
13
|
+
- **用户**:作者多选列表来自 `git shortlog`(带提交数、模糊搜索、最活跃 500 位、超出如实标注),**跟随当前 ref**——名单里的人必然搜得到;
|
|
14
|
+
- **日期**:预设(今天 / 最近 7 天 / 最近 30 天)+ **自绘日历**(月导航、今日高亮、上下月补位、之后/之前切换选界、区间可单独清除;原生 date 控件在 Windows 观感老旧且 bundle 纯度门禁禁第三方库,日历网格为纯函数、全主题 token 化);
|
|
15
|
+
- **路径**:目录树**含文件叶子**(「这个文件什么时候改过」一键可查;单目录 100 文件截断明示)+ 搜索框(扁平结果,文件在前、全路径大小写不敏感、根目录文件可搜)。勾选是**三态勾选树**语义:勾目录即覆盖并勾选其下全部文件、吸收已勾的子文件(chips 只留目录一条);在已勾目录下取消某文件则级联拆分为其余兄弟;目录框有半选态。
|
|
16
|
+
- **历史分支选择器新增「全部分支」**:搜「某人干了什么」不必先知道在哪个分支——过滤在所有 ref 上执行(IDEA 同款),名单同步。
|
|
17
|
+
- 打字与点选**双向同步**写同一个过滤器,防抖 300ms、在飞请求取消、条件变化自动回第 0 页。
|
|
18
|
+
- **文件列表按关键字过滤**:文件树工具栏新增放大镜,展开一行过滤框——变更页、历史页某个提交的文件、对比页都能用。一个提交动了一百多个文件时,那不是列表,是滚动条。
|
|
19
|
+
- **多关键字空格分隔、与关系、不看顺序**:`panel css` 能找到 `src/client/GitWorkbenchPanel.module.css`——路径长到需要过滤的时候,人本来就是这么半记半打的,而单串子串匹配偏偏在这种路径上失灵。
|
|
20
|
+
- **智能大小写**:全小写忽略大小写,一旦打了大写字母就当真——`README` 不该匹配 `readme-generator`,`readme` 仍要找得到 `README.md`。逐个关键字判断,不是整条查询一起判。
|
|
21
|
+
- 计数改口播报收窄(`2 / 6 文件`);过滤期间**忽略折叠状态**,否则命中的文件躲在二十分钟前折起的目录里,看着就是「没有匹配」;根勾选框只对**看得见的行**动手(勾选即 git 调用,「全部暂存」不该伸手到被过滤掉的文件上);关掉过滤框即清空条件——藏起来的输入框还留着条件,等于让面板处于过滤态而唯一的解释被折走了;换提交/换工作树自动清空,否则针对上一个提交打的关键字会把下一个提交的文件藏掉大半。
|
|
22
|
+
- **逐文件撤回改动(IDEA 的 Rollback)**:变更页的文件行悬浮即出现撤回按钮,把这一个文件带回上次提交时的样子——改过的还原、从未提交过的删除、误删的找回、改名的改回旧名。语义与 IDEA 一致:**不问暂存与否**,索引和工作区一起回退。目录不给这个手势——不可逆的操作不配一个能连坐整棵子树的入口。
|
|
23
|
+
- **弹窗说的是后果,不是「确定吗」**:点击不动手,先问 host「撤回这个文件会发生什么」,拿到的答案才决定弹窗措辞。抽屉里的文件行是上一次轮询的样子,而「还原成上次提交的内容」和「离开磁盘且找不回来」正是这次询问的全部内容——恰恰是一行过期数据最容易搞错的地方。找回被删文件(纯赚)不弹窗:把确认框摆在纯收益前面,是教人闭眼点确认。
|
|
24
|
+
- **host 不信客户端的说法**:执行前用一次全树 `git status` 重新推导计划(全树而非 pathspec:git 靠「一删一增」配对才认得出改名,只放行其中一半会把「撤销改名」读成「还原一个、删掉另一个」);弹窗期间文件被别人改了,重新推导的后果与你答应的那个对不上,就什么都不做。
|
|
25
|
+
- **全程没有一句危险拼写**:没有 `clean`、没有 `reset --hard`、没有 `checkout -f`、没有 `--force`——只有 `git restore` 加单个 pathspec(`--` 之后),删除走文件系统且路径先被拒绝绝对路径、盘符、UNC 前缀和任何 `..` 段,落地前再按解析后的真实路径复查一遍是否还在工作区内。单元测试扫描本模块能产出的每一条计划来守这条线。
|
|
26
|
+
|
|
27
|
+
### 修复
|
|
28
|
+
|
|
29
|
+
- **裸日期时区赌博**:Windows 上 git 对裸 `--since=2026-08-18` 的解析可能把当天提交全部排掉;host 现在把 `yyyy-mm-dd` 展开为全天(`T00:00:00` / `T23:59:59`),选中一天即指一整天。
|
|
30
|
+
- **git 失败不再静默成「没有匹配」**:非法正则 / 日期等让 `git log` 报错时,空态区直接显示 `git log failed (exit N): <stderr>`。
|
|
31
|
+
- **作者名单曾用 `--all` 而列表走单 ref**:名单里看得见的人只在其他分支有时永远搜不到(中文作者的提交全在别的分支时,现象酷似「中文过滤坏了」——逐层排查证明中文参数完好到达 git,是分支覆盖问题)。
|
|
32
|
+
- 漏斗按钮并入共享按钮词汇表(并修正修饰类优先级),筛选框放开尺寸占满页签头。
|
|
33
|
+
- **日期预设是未主题化的原生按钮**:`.funnelPreset` 从未加入共享按钮词汇表,「今天 / 最近 7 天 / 最近 30 天」以浏览器默认灰按钮渲染——深色抽屉里唯一一块外来 chrome,且第三个按钮被面板宽度截断。
|
|
34
|
+
- **日历跟随浏览器语言而非抽屉语言**:月份标题与星期行取自 `Intl.DateTimeFormat(undefined, …)`,于是英文界面在中文系统上印出「2026年8月」与「一二三四五六日」。语言标记改由词典自身提供(`filterLocale`)。
|
|
35
|
+
- **漏斗弹层重做**:面板此前自身可滚动、内部列表又硬卡 240px——331px 的盒子里套一根滚动条,而锚点明明留出了约 750px;现在弹层是单一滚动子级的 flex 列,列表吃满可用高度(作者一屏由 9 位增至 28 位)。原生勾选框换成 token 化的三态勾选(半选为横杠),目录补上文件夹字形使目录名与文件名对齐成一列,缩进不再被 `.pathChildren` 的外边距重复计算(每级 29px → 14px),那条画在 `--gs-panel` 上的 `--gs-border-soft` 导轨(在 GitHub 配色里与 `--gs-raise` 同值,hover 即消失)随之移除;页签头改为分段控件,「之后/之前」以带标题的矩形轨道区分于页签,日历标注区间内的日期,弹层新增页脚「已选 N 项 / 清除全部」——此前唯一的反馈是被弹层挡住的 chips 行。
|
|
36
|
+
- **按路径过滤后点开提交,默认没选中被过滤的那个文件**:默认选中的回退一直是「该提交的第一个文件」,与过滤条件无关——`path:xx/aa/dd.ts` 筛出一串提交,点进去打开的却是排序最靠前的那个,而过滤所针对的文件在树里没有高亮。现在的优先级(`active-file.ts` 纯函数):**已有选中项**(显式点击优先于过滤,且在过滤列表里逐条下移时保持不动——这正是过滤的意义)→ **被精确点名的文件**(勾 `xx/aa/dd.ts` 是对一个文件的表态,勾 `xx` 是对一片区域的表态,前者更具体)→ **过滤目录下的文件** → **第一个文件**(原行为)。同层并列时按提交自身的文件顺序取最靠上的一行,而不是过滤器里的顺序——后者只是勾选先后的产物,界面上从不显示。
|
|
37
|
+
- **目录/文件图标铺到所有列出文件的地方**(变更页文件树、历史页提交文件树、对比页),此前只有过滤器的路径树有;文件行的状态徽章随之从行首移到行尾、与 ±行数 同列,否则行首会并排出现两个图标。
|
|
38
|
+
- **路径树的目录/文件图标改为 IntelliJ New UI 风格**:从 CSS 边框拼的小方块换成内联 SVG——16px 网格、1px 描边、无填充、圆角接合的轮廓图标(新版 IDEA 从旧的实心剪影改成了描边)。两者共用 16px 槽位所以目录名与文件名对齐成一列;描边坐标落在 .5 上,1px 线压在整像素而非跨两像素。仍是手绘形状、不引入图标包(bundle 纯度门禁)。
|
|
39
|
+
|
|
40
|
+
### 行为变更
|
|
41
|
+
|
|
42
|
+
- 按人搜索只匹配**作者**(与 IDEA 一致;git 无法下推「作者或提交者」并集)。提交者仍完整显示在悬浮详情卡。
|
|
43
|
+
|
|
44
|
+
## [0.1.3] - 2026-08-18
|
|
45
|
+
|
|
46
|
+
### 修复
|
|
47
|
+
|
|
48
|
+
- **空目录裸 `npm i @young1lin/dsh-ui-gitworkbench` 报 E404(`@deepseek-ai/dsh-compact` not found)**:包的 peerDependency 之前全写 `*`,而 npm 7+ 自动安装 peer 时 `*` 按 **`latest` dist-tag** 解析——`@deepseek-ai/*` 全系的 `latest` 至今仍指 8 月 10 日的 `0.0.1-rc.1` 老线,那条线依赖一个从未发布到 npm 的 `dsh-compact`,于是任何不在 dsh profile 工作区里的裸安装必炸(8 月 17 日 dsh 发布 0.1.0-rc.7 后更多人在新环境首次安装撞上)。peer 范围改为显式区间:cordis `^4.0.1-rc.1`、dsh 系 `^0.1.0-rc.2`,不再依赖 dist-tag;`0.1.0-rc` 线的依赖链已实测可独立解析。官方通道 `dsh plugin --profile web add` 不受影响(profile 工作区自带全部 peer)。**0.1.2 的临时绕过**:`npm i @young1lin/dsh-ui-gitworkbench --legacy-peer-deps`。
|
|
49
|
+
|
|
5
50
|
## [0.1.2] - 2026-08-17
|
|
6
51
|
|
|
7
52
|
### 修复
|
package/CHANGELOG_EN.md
CHANGED
|
@@ -2,6 +2,51 @@
|
|
|
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.4] - 2026-08-18
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **History: who, and exactly when.** Rows show the author beside the abbreviated hash; the hover card adds author, committer (only when git recorded someone other than the author — rebases, cherry-picks, maintainer-applied patches), and the exact commit time (`%cI`, rendered in your browser's own timezone — no more "3 weeks ago" as the only answer).
|
|
10
|
+
- **IDEA-style pushdown history filtering**: criteria compile straight into `git log` arguments (`--author` / `--grep` / `--since` / `--until` / pathspecs) and match over **all history** before paging — not just the pages already on screen. A filtered page is still one contiguous walk, so the lane graph stays on. Matching is case-insensitive throughout; literals are regex-escaped (`a.b` matches `a.b`); the text criterion has a regex toggle.
|
|
11
|
+
- **Query-box grammar**: `user:name` (repeatable, OR), `path:dir`, `after:` / `before:` dates (git approxidate — "2 weeks ago" works), bare words match the message; recognized criteria render as removable chips with a one-click *Clear all*; quotes wrap values with spaces.
|
|
12
|
+
- **"Filter by" funnel with section tabs** (Users N / Date • / Paths N — constant height, each tab carries its own active-criteria count):
|
|
13
|
+
- **Users**: multi-select from `git shortlog` (counts, fuzzy search, busiest 500 with the cap stated) — walking the **current ref**, so everyone listed is findable;
|
|
14
|
+
- **Date**: presets (Today / Last 7 / Last 30 days) plus a **hand-rolled calendar** (month navigation, today accent, neighbouring-month days, After/Before toggle arming which bound a click lands in, per-bound clear — the native date widget is dated on Windows and the bundle's purity gate forbids libraries; the grid is a pure function styled entirely in theme tokens);
|
|
15
|
+
- **Paths**: a directory tree **with file leaves** ("when did this file change" in one tick; a directory past 100 files truncates visibly) plus a search box (flat results, files first, case-insensitive over the full path, root-level files included). Ticking is **tri-state checkbox-tree** semantics: a folder tick covers and visibly checks everything under it and absorbs files already ticked inside it (one chip, the folder's); unticking a file under a checked folder cascades out to its siblings; folders show a partial state.
|
|
16
|
+
- **The history ref picker gains "All branches"**: finding what someone did no longer requires knowing which branch holds it; the roster follows.
|
|
17
|
+
- Typing and ticking write the SAME filter (both ways), debounced 300ms, in-flight requests cancelled, criteria changes reset to page 0.
|
|
18
|
+
- **Filter the file list by typing at it**: a magnifier in the tree toolbar opens a filter row — in the changes tree, in a commit's files under History, and in Compare. A commit that touched 140 files is a scroll, not a list.
|
|
19
|
+
- **Space-separated terms are ANDed, in any order**: `panel css` finds `src/client/GitWorkbenchPanel.module.css`, which is how anyone types when they half-remember a path — and is what a single-substring match gets wrong for exactly the paths long enough to need filtering.
|
|
20
|
+
- **Smart case**: an all-lowercase query ignores case, and the moment you type a capital it counts. `README` should not match `readme-generator`; `readme` should still find `README.md`. Decided per term, not for the whole query.
|
|
21
|
+
- The count reports the narrowing (`2 / 6 files`); a filtered tree **ignores the fold state**, since matches hidden behind a directory collapsed twenty minutes ago read as "no matches"; the root tick acts on the **visible rows only** (a tick IS a git call, and "stage all" must not reach past a filter into files the pane is hiding); closing the box clears the query, because a hidden box still holding one leaves the pane filtered with its only explanation folded away; and switching commit or worktree clears it too, or a query typed against one commit hides most of the next one with nothing on screen saying why.
|
|
22
|
+
- **Roll one file back (IDEA's Rollback)**: hovering a row in the changes tree reveals a roll-back button that takes that one file to its committed state — a modification restored, a never-committed file deleted, a deleted file recovered, a rename undone. IDEA's semantics: it **does not ask about staging**, and takes the index and the working tree back together. Directories deliberately get no such gesture — the irreversible action does not get an entry point that can take a subtree with it.
|
|
23
|
+
- **The dialog states the consequence, not "are you sure"**: the click does not act. It asks the host what rolling this file back WOULD do, and that answer supplies the wording. A row in the drawer is a poll old, and the difference between "goes back to its committed content" and "leaves the disk and cannot come back" is the entire subject of the question — which is exactly what a stale row gets wrong. Recovering a deleted file shows no dialog at all: a confirmation in front of a pure gain is how people learn to click through confirmations.
|
|
24
|
+
- **The host does not trust the client's account of the file**: the plan is re-derived from a fresh whole-tree `git status` before anything runs (whole-tree, not a pathspec: git pairs a deletion with an addition to see a rename, and admitting only one half turns "undo the rename" into "restore one, DELETE the other"). If the file changed while the dialog was open, the freshly derived consequence no longer matches the one you agreed to, and nothing is done.
|
|
25
|
+
- **No destructive spelling anywhere in the path**: no `clean`, no `reset --hard`, no `checkout -f`, no `--force` — only `git restore` with a single pathspec after `--`. Deletes go through the filesystem, and a path is refused if it is absolute, carries a drive letter or UNC prefix, or holds any `..` segment; the resolved path is re-checked against the worktree root immediately before the file is removed. A unit test scans every plan this module can produce to hold that line.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- **Bare-date timezone roulette**: on Windows, git's parse of a bare `--since=2026-08-18` can exclude that very day's commits; the host now expands `yyyy-mm-dd` to the whole day (`T00:00:00` / `T23:59:59`).
|
|
30
|
+
- **A failed log no longer masquerades as "no match"**: an invalid regex or date shows `git log failed (exit N): <stderr>` in the empty state.
|
|
31
|
+
- **The author roster once used `--all` while the list walked one ref**: people visible in the menu could be unmatchable forever (with a Chinese author whose commits all live on other branches this read convincingly as "Chinese filtering is broken" — layer-by-layer probing proved the pattern reaches git intact; branch coverage was the whole story).
|
|
32
|
+
- The funnel button joined the shared button vocabulary (modifier specificity fixed); the filter box fills the pane head.
|
|
33
|
+
- **The date presets were unthemed native buttons**: `.funnelPreset` never joined the shared button vocabulary, so Today / Last 7 days / Last 30 days rendered as the browser's default grey buttons — the one patch of foreign chrome in the drawer, with the third one clipped by the panel's width.
|
|
34
|
+
- **The calendar followed the browser's language, not the drawer's**: the month title and weekday row came from `Intl.DateTimeFormat(undefined, …)`, so an English drawer on a zh-CN machine printed "2026年8月" over 一二三四五六日. The tag now comes from the dictionary itself (`filterLocale`).
|
|
35
|
+
- **The funnel popup, reworked**: the panel used to scroll itself AND cap its list at 240px — one scrollbar nested in a 331px box while the anchor had left ~750px available; it is now a flex column with a single scrolling child and the list takes the height that was already there (9 authors per screen became 28). Native checkboxes became tokenised tri-state ticks (a bar for partial); directories gained the folder glyph files already had, so names line up in one column; indentation stopped being double-counted by `.pathChildren`'s margin (29px per level → 14px), which also retired the indent rail drawn in `--gs-border-soft` over `--gs-panel` (the same value as `--gs-raise` in the GitHub palettes, so it vanished under hover). The tab strip is a segmented control, After/Before is a captioned rect track that no longer mimics it, the calendar tints the days between the bounds, and the popup gained a footer — "N selected / Clear all" — where the only feedback used to be the chip row the popup covers.
|
|
36
|
+
- **A path-filtered commit did not open on the filtered file**: the fallback selection was always "the commit's first file", filter or no filter — so `path:xx/aa/dd.ts` narrowed the list to commits about that file, and clicking one opened whatever sorted first while the file the filter was ABOUT sat unhighlighted. The order now (`active-file.ts`, pure): **the existing selection** (an explicit click outranks the filter, and stepping down the filtered list stays put — which is the point of filtering) → **a file the filter names exactly** (ticking `xx/aa/dd.ts` is a statement about a file; ticking `xx` is one about a region, and the more specific intent wins) → **a file under a filtered directory** → **the first file** (the old behaviour). Ties inside a tier go to the commit's own file order, so the highlight lands on the topmost matching row — not to filter order, which is an artifact of ticking sequence and is never shown.
|
|
37
|
+
- **Folder and file icons now appear everywhere files are listed** (the changes tree, the history commit tree, compare), where only the filter's path tree had them; the file row's status badge moved from the head of the row to its tail, beside the line counts, so the row does not lead with two glyphs.
|
|
38
|
+
- **The path tree's folder and file icons follow IntelliJ's New UI idiom**: the CSS-border boxes became inline SVG — a 16px grid, 1px strokes, no fill, rounded joins, outlines where the old UI shipped filled silhouettes. Both share one 16px slot so folder and file names line up in a single column, and every straight edge sits on a .5 coordinate so the stroke lands on one pixel instead of straddling two. Still hand-drawn shapes in that language, not an icon package (bundle purity gate).
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- Person search matches the **author only** (IDEA parity; git has no author-OR-committer pushdown). The committer stays visible in the hover card.
|
|
43
|
+
|
|
44
|
+
## [0.1.3] - 2026-08-18
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- **A bare `npm i @young1lin/dsh-ui-gitworkbench` in an empty directory died with E404 (`@deepseek-ai/dsh-compact` not found).** Every peerDependency was `*`, and when npm 7+ auto-installs a peer, `*` resolves through the **`latest` dist-tag** — which every `@deepseek-ai/*` package still points at the August 10 `0.0.1-rc.1` line, whose dependency on `dsh-compact` was never published to npm. Any install outside a dsh profile workspace therefore 404ed (dsh's 0.1.0-rc.7 release on August 17 sent more people into fresh-environment installs and into the trap). Peer ranges are now explicit — cordis `^4.0.1-rc.1`, the dsh packages `^0.1.0-rc.2` — so resolution no longer consults dist-tags; the `0.1.0-rc` dependency chain is verified to resolve standalone. The official channel, `dsh plugin --profile web add`, was never affected (the profile workspace already carries the peers). **Workaround while on 0.1.2**: `npm i @young1lin/dsh-ui-gitworkbench --legacy-peer-deps`.
|
|
49
|
+
|
|
5
50
|
## [0.1.2] - 2026-08-17
|
|
6
51
|
|
|
7
52
|
### Fixed
|
package/README.md
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
每个会话的头部都有一枚状态卡,显示当前分支、领先/落后和增删计数。点开它,右侧滑出一张工作台面板,当前 worktree 的改动一览无余:
|
|
8
8
|
|
|
9
|
-
- **变更**:可折叠的文件树,配逐文件 diff——双列行号、词级高亮、Shiki
|
|
10
|
-
- **历史**:提交列表 / 文件树 / diff
|
|
9
|
+
- **变更**:可折叠的文件树,配逐文件 diff——双列行号、词级高亮、Shiki 语法着色;树顶可打关键字过滤文件列表(多词与关系、智能大小写),文件行悬浮可一键撤回到上次提交(IDEA 的 Rollback,弹窗先说清后果);
|
|
10
|
+
- **历史**:提交列表 / 文件树 / diff 三栏并排,滚动到底自动翻页;行内带作者、悬浮卡带精确时间;IDEA 式过滤(`user:` / `path:` / `after:` 输入语法,或作者 / 日期 / 路径分区漏斗弹层),条件编译进 `git log`、全历史匹配、车道图常驻,另有「全部分支」;
|
|
11
11
|
- **对比**:任选两个分支互相比较;
|
|
12
12
|
- **提交与同步**:树上勾选文件就是真实的 `git add` / `git restore --staged`,配合提交框和 fetch / pull / push 同步条,一次提交加推送全程不用离开面板;
|
|
13
13
|
- **外观**:七套主题族各带亮暗,默认跟随系统;支持虚化背景图和自定义 CSS,按「项目 / 全局」两个作用域保存,项目优先。
|
|
@@ -86,6 +86,8 @@ irm https://raw.githubusercontent.com/young1lin/dsh-ui-gitworkbench/main/scripts
|
|
|
86
86
|
| agent 工具 `worktree_enter/exit/status`(模型可调) | ✅ | 真实会话冒烟 `scripts/llm_smoke.py`:模型调 enter → `.agents/worktrees/llm-smoke` 出现;exit(remove) → 消失 |
|
|
87
87
|
| 宿主 worktree RPC(enter/exit/status/sessionWorktree)+ 绑定文件 | ✅ | `python scripts/probe_worktree.py`:scratch 仓库断言 + 真仓库冒烟 + 再进入分支复用,ALL PASS |
|
|
88
88
|
| 状态卡绑定标记(树形图标;徽标文字与分支重名时省略)+ 头部 worktree 选择器 | ✅ | `python scripts/verify_worktree_ui.py`:6 步 UI 探针(绑定标记、头部路径、选择器切换、折叠/选中回归) |
|
|
89
|
+
| 历史过滤(作者 / 日期 / 路径下推 `git log`、「全部分支」、日历与三态路径树) | ✅ | `python scripts/verify_history_feature.py`:11 步 UI + host 探针全过(中文作者、All-branches、日历选界、目录吸收文件勾选、诚实空态) |
|
|
90
|
+
| 单文件撤回(Rollback)与文件列表关键字过滤 | ✅ | 对 live app 实测:撤回弹窗措辞随 host 实时推导的后果变化、取消不动手、执行后 fixture 回静息态;过滤框多词 AND、忽略折叠、根勾选只动可见行 |
|
|
89
91
|
| 客户端半被类型检查 | ✅ | `tsconfig.client.json` 进了 `bundle`/`typecheck`;曾故意写坏一处,确认报 `TS2322` |
|
|
90
92
|
| 主题 7 族 × 亮暗 + 跟随系统明暗 | ✅ | `tests/theme-palettes.test.ts` 把 `themes.ts` 与 `.module.css` 互扣(两个方向都验过会红);`lib/client.js` 含全部 14 套调色板 |
|
|
91
93
|
| 背景图 / 自定义 CSS 的项目+全局存储 | ✅ | 对**构建产物** `lib/index.js` 跑 styleGet/styleSet 全流程(临时 HOME,18/18 PASS):读写、项目优先、越界钳制、恶意 image 拒绝、清空删记录、非仓库拒绝、两作用域并发写不互相覆盖 |
|
|
@@ -168,14 +170,21 @@ export function apply(ctx) {
|
|
|
168
170
|
- **agent 工具**:同一份逻辑用 `ctx.tools.register(defineTool({...}))` 注册成 `worktree_enter/exit/status`,sessionId/cwd 取自 `exec.agent?.session`(**不接受**模型传参)——注册要点见 §6.10,schema 限制见 §6.11。
|
|
169
171
|
- **客户端跟随**:`GitWorkbenchPanel` 每轮拉 stats 的同时拉 `worktreeStatus(sessionId, cwd)`(绑定 + 仓库全部 worktree 一次拿到,agent 在 dsh 外面建的 worktree 也会跟进列表);有绑定 → 状态卡亮出绑定标记(树形图标;分支与徽标文字重名时省略后者)、stats 改传绑定的 worktree 绝对路径;面板头部的 worktree 选择器按分支列出所有源,**只切显示对象、不动绑定**。树的展开状态跨切换、跨轮询保留;选中在切换源时**有意重置**——旧 worktree 的路径不能漏进新树的选中(§6.0c)。
|
|
170
172
|
|
|
171
|
-
### 2.5 写操作:暂存 / 提交 /
|
|
173
|
+
### 2.5 写操作:暂存 / 提交 / 同步 / 撤回(`src/git-ops.ts` + `src/discard-ops.ts` + 宿主 9 个 `@Remote`)
|
|
172
174
|
|
|
173
175
|
- **勾选就是 git 调用**:勾一个文件=`git add -- <path>`,取消=`git restore --staged -- <path>`,立即生效。argv 全部数组构造(无 shell,引号不是攻击面),路径一律放 `--` 之后并拒绝前导 `-`(文件可以合法叫 `-f`,位置参数传进去就成了选项);全库没有 `--force`/`reset --hard`/`clean` 任何拼写——丢提交类操作需要的是专门的确认设计,不是碰巧排在旁边的按钮。
|
|
174
176
|
- **点击即显、不丢点击**:勾选走乐观更新 + 队列(`stage-tree.ts` 的 `nextBatch` 按动作聚批,一次 drain 只发一个 git 调用——宿主一次调用 ~300ms,等它返回再画勾就是用户投诉的「超级卡」),120ms 内连点两下都会入队生效;轮询回包经 `settledTicks` 对账后落定。
|
|
175
177
|
- **提交**:`commit(worktreePath, message, amend, signal)`——消息整段作一个 argv 元素传 `-m`(多行 body 是常态,拆分才是风险),绝不 `-a`:面板有自己的暂存区,全量扫进去等于让分区变成摆设。
|
|
176
178
|
- **同步**:`syncStatus`(branch/upstream/ahead/behind + hasRemote,读 `git status` 而非 `rev-list --count`——「没配 upstream」和「与 upstream 齐平」的计数都是 0,只有前者决定 push 要不要 `--set-upstream`)、`fetch --prune`(远端删掉的分支别再算作待拉取)、`pull --ff-only/--rebase/--no-rebase`(模式永远显式:按钮写什么就跑什么,不读用户的 pull.rebase 配置)、`push`(绝不 force;无 upstream 时 `--set-upstream origin <branch>`;被拒归类为 `diverged`,答案是先 pull 而不是覆盖别人的工作)。
|
|
179
|
+
- **单文件撤回(IDEA 的 Rollback)**:`discardPlan` / `discardFile`,计划推导在 `src/discard-ops.ts`(纯函数)。语义与 IDEA 一致:**不问暂存与否**,索引与工作区一起回退——改过的还原、未提交过的删除、误删的找回、改名撤销;目录不提供这个手势。计划由 host 用**全树** `git status` 现场推导(git 靠「一删一增」配对才认出改名,带单文件 pathspec 的 status 只看到一半,会把「撤销改名」错读成「还原一个 + 删掉另一个」,见 §6.16);弹窗措辞来自推导出的后果(找回已删文件是纯收益,不弹窗);执行前重推一遍并核对后果一致,文件变了就什么都不做。危险拼法禁令同上且更严:只有 `git restore` 加单个 pathspec(`--` 之后),删除走文件系统但拒绝绝对路径 / 盘符 / UNC / `..` 并按解析后路径复查在工作区内——`tests/discard-ops.test.ts` 扫描本模块可产出的每条计划守这条线。
|
|
177
180
|
- **失败要说人话**:`classifyFailure` 把 stderr/exit 归类为 auth / no-upstream / diverged / conflict / nothing-to-commit / dirty,原始文本随行返回——归类是提示,不替代证据。子进程环境关掉全部凭据提示(`GIT_TERMINAL_PROMPT=0`、`GCM_INTERACTIVE=never`、askpass 置空):`stdin:'ignore'` 不会把交互提示变成错误,只会变成没人能回答的等待,而那等待挂在宿主进程里——一个过期的 token 就能挂死整个插件 30s。
|
|
178
181
|
|
|
182
|
+
### 2.6 历史过滤(宿主 `src/log-filter.ts` + `src/shortlog.ts`;客户端 `log-filter-query.ts` / `calendar.ts` / `dir-tree.ts` / `path-select.ts`)
|
|
183
|
+
|
|
184
|
+
- **条件编译成 `git log` 参数**(`log-filter.ts`:统一 `-i -E` 方言、字面量转义、`--author` 逐人、approxidate `--since`/`--until`、pathspec 放 `--` 之后),在**全部历史**上匹配后再分页——不是只筛已加载的页;过滤后的翻页仍是单次连续游走,车道图不断。裸 `yyyy-mm-dd` 由 host 展开为全天(§6.15);`git log` 失败原样透出 stderr(exit + 尾部),不静默成「无匹配」。
|
|
185
|
+
- **两个入口写同一个过滤器**:输入框语法(`user:` / `path:` / `after:` / `before:` + 可删除 chips,`log-filter-query.ts`)与漏斗弹层(作者来自 `git shortlog` 且**跟随当前 ref**——名单里的人必然搜得到;自绘日历 `calendar.ts` 纯函数月格;路径树 `dir-tree.ts` 聚合 + `path-select.ts` 三态勾选:勾目录覆盖并吸收子文件,目录有半选态)。防抖 300ms、在飞请求取消、条件变化回第 0 页。
|
|
186
|
+
- **「全部分支」** = `--all` 哨兵(ref 不能以 `-` 开头,无歧义),ref 选择器与作者名单同步。按人搜索只匹配**作者**(git 没有「作者或提交者」并集下推,IDEA 同款),提交者完整显示在悬浮卡。
|
|
187
|
+
|
|
179
188
|
---
|
|
180
189
|
|
|
181
190
|
## 3. 文件布局
|
|
@@ -189,11 +198,14 @@ harness-worktree/
|
|
|
189
198
|
tsdown.config.ts tsdown 构建【客户端半】用(closure-factory bundle + CSS Modules 插件)
|
|
190
199
|
vitest.config.ts 排除 .agents/**(worktree 是整仓副本,否则同一套测试被收集多遍)
|
|
191
200
|
src/
|
|
192
|
-
index.ts 宿主半:GitWorkbenchService(TypertRemoteService + @Remote:stats/fileDiff/commits/compareRefs/commitStats/worktree*/style*/syncStatus/stage/unstage/commit/fetch/pull/push)+ defineTool 三工具
|
|
201
|
+
index.ts 宿主半:GitWorkbenchService(TypertRemoteService + @Remote:stats/fileDiff/commits/authors/repoTree/compareRefs/commitStats/worktree*/style*/syncStatus/stage/unstage/discardPlan/discardFile/commit/fetch/pull/push)+ defineTool 三工具
|
|
193
202
|
atomic-json.ts 崩溃安全的 JSON 写入(tmp+rename + Windows EPERM 退避),绑定文件与样式文件共用
|
|
194
203
|
commit-cache.ts 内容寻址缓存:commit hash 指向不可变内容,只需容量上限、不需失效
|
|
195
204
|
git-ops.ts 写操作的 argv 构造 + stderr 归类(纯函数、不 spawn)——见 §2.5
|
|
196
205
|
git-log.ts `--pretty` 日志与 porcelain 状态头的解析(纯函数)
|
|
206
|
+
log-filter.ts 历史过滤条件 → `git log` 参数的编译 + 裸日期展开为全天(纯函数,§2.6)
|
|
207
|
+
shortlog.ts 作者名单:`git shortlog -sne` 输出解析、按活跃度排序截断(纯函数)
|
|
208
|
+
discard-ops.ts 单文件撤回的计划推导(全树 status → restore/delete 计划 + 路径防线,纯函数,§2.5)
|
|
197
209
|
style-store.ts 背景图 + 自定义 CSS 的两作用域存储与校验(~/.dsh/gitworkbench-style.json)
|
|
198
210
|
worktree.ts worktree 纯逻辑:绑定文件读写(tmp+rename 原子、EPERM 重试)、名称/分支/目录推导、porcelain 解析、`isRefName`
|
|
199
211
|
types/dsh-shim.d.ts ambient 声明:让 tsc 在没装 @deepseek-ai/* 时也能编译(cordis/subprocess 的宽松类型)
|
|
@@ -206,16 +218,25 @@ harness-worktree/
|
|
|
206
218
|
diff-model.ts 统一 diff 行解析 + 词级变更区间(纯函数)
|
|
207
219
|
commit-graph.ts 提交图的泳道分配(纯函数)
|
|
208
220
|
worktree-view.ts worktree/分支列表的展示推导(纯函数)
|
|
221
|
+
log-filter-query.ts 过滤输入框语法(user:/path:/after:/before: → 条件对象 + chips,纯函数)
|
|
222
|
+
commit-filter.ts 悬浮卡的精确时间渲染(`%cI` → 查看者时区,纯函数)
|
|
223
|
+
dir-tree.ts 路径选择器的目录树聚合(ls-tree 平铺 → 目录 + 文件叶子,纯函数)
|
|
224
|
+
path-select.ts 三态勾选树语义(勾目录吸收子文件、拆分级联、半选态,纯函数)
|
|
225
|
+
calendar.ts 自绘日历的月格推导(纯函数,全主题 token 化)
|
|
226
|
+
active-file.ts 过滤后点开提交的默认选中文件排序(已有选中 > 精确点名 > 目录之下 > 首个,纯函数)
|
|
227
|
+
file-filter.ts 文件列表关键字过滤(多词 AND、逐词智能大小写,纯函数)
|
|
209
228
|
highlight.ts Shiki 封装:扩展名→语法、主题映射、语法包按需加载
|
|
210
229
|
op-feedback.ts 写操作按钮反馈的时序常量(忙碌提示、过短操作不禁用)
|
|
211
230
|
themes.ts 主题模型:族列表、明暗解析、两作用域样式解析、localStorage 值校验(无 CSS/React 依赖,便于测试)
|
|
212
231
|
locales.ts zh / en 两份词典
|
|
213
|
-
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
|
|
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(撤回计划推导 + 危险拼法扫描)
|
|
214
233
|
scripts/
|
|
215
234
|
probe_worktree.py 宿主 RPC 探针:scratch 仓库全流程 + 真仓库冒烟 + 再进入分支复用
|
|
216
235
|
verify_worktree_ui.py UI 探针:状态卡标记/头部路径/选择器切换/折叠回归 6 步(经真实页面 RPC 回放)
|
|
217
236
|
llm_smoke.py 真实 LLM 冒烟:让模型在会话里调 worktree_enter/exit,看目录出现/消失
|
|
218
|
-
|
|
237
|
+
verify_turn_refresh.py UI 探针:抽屉关着时回合结束自动刷新状态卡(0.1.2 的刷新链路)
|
|
238
|
+
verify_history_feature.py UI+host 探针:历史过滤两半(条件下推 + 输入框/漏斗/诚实空态)11 步
|
|
239
|
+
(五个 .py 探针为本地集成脚本:需连真实 dsh 实例与 scratch 仓库,内嵌本机路径——已 gitignore,不入库、不随包发布)
|
|
219
240
|
cordis.patch.yml 一行 insert,把宿主 entry 挂进 web profile
|
|
220
241
|
README.md 本文件
|
|
221
242
|
README_EN.md 英文版(面向使用者与维护者;深度细节仍以本文为准)
|
|
@@ -346,6 +367,18 @@ window.__ModuleLoader__.load({ id: "@young1lin/dsh-ui-gitworkbench", factory: (r
|
|
|
346
367
|
### 6.13 宿主环境可能没有 git(PATH 缺失)
|
|
347
368
|
宿主 RPC 返回 `git status failed (exit N): <stderr>`(本插件的报错都带 exit code + stderr 尾部)时,先看 stderr——常见是宿主进程环境异常/git 不在 PATH,而不是目录真的不是仓库(2026-08-15 实例:目录明明是仓库却报 not a git worktree,重启 dsh web 换个健康环境即愈)。**报错透出 stderr 是定位这类问题的唯一手段**,新加 git 调用时照抄这个格式。
|
|
348
369
|
|
|
370
|
+
### 6.14 发布的 peer 范围不能写 `*`——`*` 按 `latest` dist-tag 解析
|
|
371
|
+
npm 7+ 自动安装 peer 时,`*` 走 **`latest` dist-tag**,不是「取版本列表最高」。`@deepseek-ai/*` 全系的 `latest` 长期停在 8 月 10 日的 `0.0.1-rc.1` 老线(那条线依赖**从未发布**的 `@deepseek-ai/dsh-compact`,公开安装必 404),能用的 `0.1.0-rc.x` 全挂 `next`。于是 0.1.2 之前任何不在 dsh profile 工作区里的裸 `npm i` 都炸 E404。规则:**peer 写显式区间**(cordis `^4.0.1-rc.1`、dsh 系 `^0.1.0-rc.2`),dsh 发新线时同步抬范围并验证 `npm pack` 出的 tarball 在空目录可装。注意 6.5 的 `auto-install-peers=false` 只管本仓库 pnpm 开发态,管不了用户侧 npm。
|
|
372
|
+
|
|
373
|
+
### 6.15 Windows 上裸 `--since=2026-08-18` 可能吃掉当天的提交
|
|
374
|
+
git 对裸 `yyyy-mm-dd` 的 `--since`/`--until` 解析带时刻语义,Windows 上一整天的提交可能全被排掉,且无任何报错。host 把裸日期展开为 `T00:00:00` / `T23:59:59` 再交给 git(`log-filter.ts`)——选中一天即指一整天,不赌平台行为。
|
|
375
|
+
|
|
376
|
+
### 6.16 带单文件 pathspec 的 `git status` 会把改名拆成「一删一增」
|
|
377
|
+
git 靠「一删除 + 一新增」的配对才认得出改名;pathspec 只放行一半时,status 报 `D` 加 `??`,而不是 `R`。任何**按 status 推导计划**的代码必须用全树 status 自行配对(`discard-ops.ts` 即因此不接受客户端传来的 status,一律重推),否则「撤销改名」会被计划成「还原一个、删掉另一个」——正好是用户没答应的那件事。
|
|
378
|
+
|
|
379
|
+
### 6.17 抽屉内新增模态层的 CSS 必须写 `.drawer > .xxx`,裸类会被压住
|
|
380
|
+
`.drawer > *:not(.resizer) { position: relative; z-index: 1 }`(布局需要)给了每个直接子元素 position 与层叠秩,裸类声明的 `position: absolute` 会输给它——遮罩被当作最后一个 flex 项排进抽屉底部的一条缝里,样式全对、位置全错、还不报错。模态遮罩一律写成 `.drawer > .confirmScrim` 这种带父作用域的选择器;`tests/drawer-chrome.test.ts` 有断言守着这条作用域与层叠秩。
|
|
381
|
+
|
|
349
382
|
---
|
|
350
383
|
|
|
351
384
|
## 7. dsh 仓库里的关键参考文件(去哪里抄)
|
package/README_EN.md
CHANGED
|
@@ -6,8 +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: dual line numbers, word-level highlights, Shiki syntax coloring.
|
|
10
|
-
- **History** — commits, file tree, and diff in three panes; scrolling to the bottom loads the next page automatically.
|
|
9
|
+
- **Changes** — a collapsible file tree beside per-file diffs: dual line numbers, word-level highlights, Shiki syntax coloring. A magnifier in the toolbar filters the list by space-separated keywords (smart case); hovering a row reveals a roll-back button that takes that one file to its committed state (IDEA's Rollback) behind a dialog that states the real consequence.
|
|
10
|
+
- **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
11
|
- **Compare** — diff any two branches against each other.
|
|
12
12
|
- **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.
|
|
13
13
|
- **Appearance** — seven theme families in light and dark (following the OS by default), plus a blurred background image and custom CSS, stored per project and globally with the project scope winning.
|
|
@@ -77,3 +77,4 @@ Releases are tag-driven: pushing a `vX.Y.Z` tag runs the CI checks and publishes
|
|
|
77
77
|
## Known limits
|
|
78
78
|
|
|
79
79
|
- The status card mounts in the `conversation.session.header.actions` slot, so it appears only once a session is actually open. In headless automation without a real session the card will not show — open a session in the UI to see it.
|
|
80
|
+
- Person search in the history filter matches the **author** only (IDEA parity — git has no author-or-committer pushdown). The committer stays visible in the hover card.
|