figmar
5e66de0296
docs(wiki): 同步 main 的对比式需求分析(40a05af)
2026-10-04 02:02:58 +08:00
figmar
73dead127f
docs(wiki): 同步 main 的对比式需求分析(2b88c85)
2026-10-04 02:00:28 +08:00
figmar
13f12c4206
docs(wiki): 同步 main 的使用者视角需求分析(2224991)
2026-10-04 01:55:37 +08:00
figmar
2a2ac96d33
docs(wiki): 项目百科随分支携带(同 main 63bcb47)+ 清掉 README 里残留的旧 fork notice
...
v0.24.1 re-base 时,README 的增量补丁把本 fork 的旧 notice 作为「纯新增」带进来了,
它不在任何冲突块内,于是与新的(v0.24.1)notice 重复出现在文件顶部。删除旧的那段,
并在 notice 末尾补上百科入口。
2026-10-04 01:19:56 +08:00
figmar
e5bbef1907
feat(sync): re-base the fork onto upstream dsh-better-sidebar v0.24.1 (fork 1.3.0)
...
Branch for hardware verification on a host that meets v0.24.1's peer range.
Base: upstream `dsh-better-sidebar` v0.24.1 (tag v0.24.1 = a2751cf ), MIT.
Measured delta carried over from the v0.19.1 line: 78 rename-only files, 11 real
edits, 10 additions. Ported with the same measurement method as the v0.19.1
re-base: build a normalized base (upstream tree + the fork rename, excluding
README.md / package.json / docs/plans/* which deliberately keep the upstream
name), extract the delta against it, then three-way apply onto the renamed
v0.24.1 tree (`git apply -3`). 13 conflicts resolved by hand.
Identity:
- version 1.3.0, SIDEBAR_SERVICE_VERSION 1.3.0 (package.json ↔ service.ts pair
is asserted by tests/service.spec.ts), forkedFrom -> v0.24.1/a2751cf.
- package.json keeps the union of both sides' metadata: upstream's new
`zustand` + `icon`/`locale` files entries, plus the fork's `scripts/switch.sh`
entry and its `forkedFrom` block.
- README.md takes upstream v0.24.1 wholesale (its own v0.24.1 changelog and all
16 sections) and keeps the fork's two deltas: the fork-notice block at the top
(now documenting the 0.2.0-rc.1+ requirement) and the fork package name.
- peerDependencies stay upstream's `^0.2.0-rc.1` — this line does NOT load on
DSH 0.1.x: the host's semver pre-check rejects a caret range across a minor
and silently disables the row (no error, no load).
Carried features, all re-verified against the new base:
- apes:* information-layer tabs (src/client/apes/) — the subtree's session feed
changed shape in 0.1.7 and the port follows the host's own migration notes in
context-types.ts: the per-session catalog is now
`projectionsBySession[id].values.subagentCatalog` (a flat entry list) instead
of 0.1.6's `subagentsByParent` catalog with `entries`/`kind`/`activity`, and
the removed `list.current` is answered by `props.scope.sessionId`. Rows are
normalized to { id, label, mode } with activity read from the durable
summaries, so catalog and byId sources render alike.
- HTML preview delivery through srcdoc (sandbox kept intact).
- Panel host mounted inside the shell's framed content viewport.
Gate: typecheck clean; build clean; 1515 passed / 9 skipped (141 files).
NOT applied to ~/.dsh/profiles/desktop — that profile runs DSH 2.0.10 with
@deepseek-ai/dsh 0.1.5-rc.2, where this line is silently disabled by design.
2026-10-04 00:58:28 +08:00
figmar
23ca3daac3
chore(sync): re-base the fork onto upstream dsh-better-sidebar v0.24.1 (rename only)
2026-10-04 00:46:18 +08:00
Atlas Zeng
a2751cfbde
Merge pull request #782 : 文件页/文件变动页 UIUX 重构 + DSH 0.2.0 适配(v0.24.1)
...
汇总自 v0.22.1 以来的全部更新:文件页多选 / Git 着色 / 新建文件夹 / 压缩下载进度 / 打开方式双源 / 菜单层级 / 性能(fs.tree 22.8→3.8ms、批量 fs.trees),文件变动页重构为层级树,删除工作区路径检测(放开权限,安全相关),DSH 0.2.0-rc.1 支持线(无运行时兼容分支),以及展开整树重建、在侧边打开、展开状态重置等修复。
CI:ci / ci-windows / plugin-mount 三绿(1-review 规则按仓库 bootstrap 免审名单由 owner 账号放行)。本地 137 文件 / 1491 用例、真实宿主 lane 9/9。
v0.24.1
2026-09-28 23:28:46 +08:00
Menghuan1918
52be73e176
test(zip): 让两条断言平台正确,修 ci-windows 红
...
ci-windows(首次在本分支跑)报 tests/zip.spec.ts 两条失败,均为**测试可移植性**问题,不是产品缺陷:
1. 「keeps a backslash as part of the file name (POSIX names are literal)」:
Windows 上反斜杠就是路径分隔符,join(root, 'a\b.txt') 得到 root\a\b.txt,父目录不存在 →
writeFileSync 报 ENOENT。该语义在 Windows 上根本不存在 → 按仓库既有约定
it.skipIf(isWin32) 跳过,并在注释里写明理由。
2. 「passes unzip -t when the binary exists」:断言 outMode === inMode & 0o644 在 Windows 上
无意义(两边 statSync().mode 都是 0o666 → expected 420, received 438)。CRC 与解压断言保留,
只把 mode 一致性放进 !isWin32 分支。
本地:tests/zip.spec.ts 37/37 通过;全量 typecheck / lint / test 绿(137 文件 / 1491 通过)。
2026-09-28 23:21:06 +08:00
Menghuan1918
0ac62b3a49
Merge origin/main (v0.22.1 与三个热修 PR) into feat/files-changes-uiux
...
冲突面 11 个文件,逐项裁决如下:
1. src/client/native/index.ts —— **取 main 版**。main 的 v0.22.1 在同一处做了更强的修复
(清理循环同样跳过 FILES_KIND,另加 `disposeSafely` 与「注册失败必须回滚已占用 id /
已建槽位」),是我们那行守卫的超集。
⚠️ 但 main 分支从来没有过我们 task-19 的 `records.attachStore(store)` 调用,整文件
采用会**静默丢掉**它(records 拿不到 store → `toggleExpanded` 直接 return → 点目录
树毫无反应),且 jsdom 单测看不见(它们自己绑 records)。已按原注释恢复该调用,并在
注释里记下这次合并教训。真实宿主 lane 证明:恢复前 `zz-expand-refresh` 红(请求为
空、`big` 不展开),恢复后 9/9 全绿。
2. package.json / dsh.plugin.json / src/client/service.ts —— 版本相关冲突取我们的
0.24.1(支持线 ^0.2.0-rc.1 不变)。
3. CHANGELOG / README(中英各一)—— 双方版本节全部保留:我们的 v0.24.1 / v0.24.0 +
**新增缺失的 v0.23.0 节**(开发线,内容随 v0.24.1 发布)+ main 的 v0.22.1。
同时修正两处事实错误:① 「0.1.7 线请固定 v0.23.0」→ **v0.22.1**(0.23.0 从未发布);
② 安装对照表里 0.1.7 行的安装命令同改。README 并补上 v0.23.0 摘要(含 ⚠️ 删除工作区
路径检测这一安全相关的行为变更)。
4. docs/external-plugin-guide.md —— 版本行取我们的(0.2.0 线)。
验证(合并后的树):pnpm typecheck / lint / test = **137 文件 / 1491 通过 / 9 跳过**
(含 main 新增的 native-registration.spec.ts);pnpm build ✓;
DSH_CMD='npx -y --package @deepseek-ai/dsh@0.2.0-rc.1 dsh' pnpm test:mount = **9/9**
(mount 5 + perf 2 + main 的 native-reload 1 + 我们的 zz-expand-refresh 1)。
2026-09-28 23:13:36 +08:00
Menghuan1918
98a446bbfc
fix(sidebar): 点击展开时文件树整体重建(两处根因)+ v0.24.1
...
用户报告:「点击展开的时候,文件树会频繁整体刷新,看起来非常难受」。
根因 1(主):src/client/native/index.ts 的 sync() 把 files 接管项当成多余注册。
它按 KIND 记账、永远不在 wanted 里,于是每次 sync 都被 dispose + 重建;而
disposeSubscriptions 同时订阅了 service 与 store,**任何会话状态写入**(展开/收起、
切 tab、拖底部工作台、选中…)都会跑一遍 sync。替换 slot 注册 = 宿主换 slot entry →
插件 tab body 被 unmount/remount → 文件树丢失层缓存、滚动位置与目录 watcher,并重新
fs.trees([root, ...expanded]) 重列整棵可见树。机械证明(临时插桩,已回退):
[probe-sync] enter live=[editor,git,subagent,sidechat,diff,files]
[probe-registerSlots] slot inject ran for dsh-better-sidebar:files
[probe-body] unmount tab3 kind=files
[probe-body] mount tab3 kind=files
修法:wantsFiles 提前,删除循环里对 files 接管项 skip(禁用 editor 时仍照旧释放)。
根因 2(次):FileTree.tsx 的 retryDir 先把该层缓存删掉再请求,行被「Loading…」
占位替换后重建——目录有外部写入(构建 / 格式化 / 模型跑 bash)时整层闪空。
修法:复用既有 force 路径 loadLevels([dir], { force: true }),保留旧行直到新答案到达
(与 refreshTick 的强制刷新路径行为一致)。
判别性证据(回退任一修复即红)
- tests/native-surface.spec.ts:三次 store 写入不得产生任何注册/注销 → 回退后
registered 6 → 12、disposed 全是 dsh-better-sidebar:files
- tests/file-tree-batch-load.spec.tsx:重列期间旧行仍在屏 → 回退后层被删空
- 新增真实宿主 lane tests/e2e/zz-expand-refresh.e2e.ts(quiescence 判据,无固定 sleep;
zz- 前缀保证它最后跑,因为它会自建 workspace + session):A1 展开只请求被展开那一层、
A2 tab body 存活(不重开 watch socket)、A3 屏上行数不归零;回退修复 1 后退出码 1
(Error: expanding a folder must ask for that folder, not the whole visible set)
修复后实测(40 子项目录,同一探针/机器/工作区)
| 阶段 | fs.trees payload | 新开 ws | DOM +/- | 被删行 | body 替换 | 层内最小行数 |
| 展开 big | [big](原 [root, big]) | 0(原 1) | +41/-1 | 0(原 45) | 0(原是) | 40(原 40) |
| 外部写入 big | [big] | 0 | +1/-0(原 +41/-40) | 0 | 0 | 40(原 0) |
| 展开 bravo | [bravo] | 0 | +2/-1 | 0(原 45) | 0(原是) | 41 |
证伪记录:新建 fs.watch(dir,{persistent:false}) 在 macOS 上无改动时 0 事件(Node 微
探针两遍 + 8 轮真实时序 + 浏览器侧从未收到 {dir} 陈旧帧)→ src/fs-watch.ts 与
use-dir-watch.ts 一行未改。
验证:pnpm typecheck / lint / test(136 文件 1486 通过 9 跳过,基线 1484 + 新增 2)/ build
全绿;DSH_CMD='npx -y --package @deepseek-ai/dsh@0.2.0-rc.1 dsh' pnpm test:mount = 8/8。
版本 0.24.0 → 0.24.1(package.json / dsh.plugin.json / SIDEBAR_SERVICE_VERSION /
README×2 / CHANGELOG×2 同步)。
2026-09-28 22:33:30 +08:00
Menghuan1918
b7825e1bd0
docs(dsh): 记录 profile overrides 必须与宿主同批抬版本的坑(0.2.0 升级实测)
...
升级 3080 后出现「加载提供商目录失败: settings service is absent」,根因是 profile 的
pnpm-workspace.yaml 里上一轮留下的 overrides '@deepseek-ai/dsh-settings': 0.1.7-rc.2——
它让 profile 顶层留住 0.1.7-rc.2 的 dsh-settings,后者用精确版本拉来 dsh-config-editor
0.1.7-rc.2 并遮蔽 bundle 自带的 0.2.0-rc.1,于是 0.2.0 的启动预检禁用 config-editor 行,
settings 行永远 pending (waiting for service: configEditor)。
已修:override 抬到 0.2.0-rc.1(profile 顶层全部收敛到 0.2.0-rc.1,.pnpm 里 0.1.7 副本归零)。
文档:适配记录新增 §5.1(含原始日志证据),AGENTS §3.0 增加「用户 profile 自己的 pin 也要
同批抬」一条。
2026-09-28 21:38:58 +08:00
Menghuan1918
b91675ae61
feat(dsh): 适配 DSH 0.2.0-rc.1(单线支持)+ v0.24.0
...
支持线从 ^0.1.7-rc.1 整体前移到 ^0.2.0-rc.1;0.1.7 线(含 npm latest 的
0.1.7-rc.2)停留在 v0.23.0。适配前实测确认这是纯增量,故本版无运行时兼容分支。
必改项(否则装不上/不加载)
- 14 条 DSH peer → ^0.2.0-rc.1。实测 caret 跨 minor 不成立:`^0.1.7-rc.1`
展开为 >=0.1.7-rc.1 <0.2.0-0,对 0.2.0-rc.1 判定 false(includePrerelease
也救不了)。判别性验证:把 peer 回退成 ^0.1.7-rc.1 后,在 0.2.0-rc.1 宿主上
`dsh plugin add` 直接拒绝并回滚包树——
"installation rejected: Plugin dsh-better-sidebar@0.24 .0 is incompatible with
dsh 0.2.0-rc.1: peerDependencies {…^0.1.7-rc.1…}";恢复 ^0.2.0-rc.1 后安装通过
- 28 个 @deepseek-ai/* devDependencies 精确钉 0.2.0-rc.1(cordis 4.0.4 /
cordis-plugin-group 1.0.4 / cordis-plugin-include 1.0.9 不变)
- 新增 @deepseek-ai/dsh-util-code-language@0.2.0-rc.1:0.2.0 的 ui-primitives
产物裸 import 它(0.1.7 的产物同样 import,只是旧树里恰好被传递提供),
不补则所有加载 ui-primitives 的 20 个 spec 在收集期失败
实测证据(写进 docs/plans/2026-09-28-dsh-0.2.0-rc.1-adaptation.md)
- 本插件消费的 19 个宿主包零值导出删除(对比 export {} / exports.x=)
- 类型面仅 3 处且全为增量:ui-primitives(DisclosureRow/TextShimmer/Tooltip
新增可选 prop、overlay 顶部内距)、dsh-session(新增 ToolCallRecovery)、
dsh-api-remotes(新增 product-analytics remote)
- 会话格式仍 v4、SUBAGENT_DESCRIPTOR_VERSION 仍 3、dsh/lib/bin.js 与
dsh-client-modules 运行时逐字节相同、web profile 客户端 inject 列表相同、
ui-primitives 裸 import 集合不变、agent-team 四包类型逐字相同
- 宿主 web profile:新增 desktop-only product-analytics/telemetry(web 上
disabled);time-context/schedule/ui-schedule(本就 disabled)移入可选
dsh-experimental-schedule-bundle;插件不依赖宿主 schedule
其余同步
- CI 与挂载 lane 钉 @deepseek-ai/dsh@0.2.0-rc.1(scripts/e2e-common.sh 的
DSH_NPX_SPEC/DSH_EXPECT_VERSION、ci.yml),注释记下「0.2.0 首个候选版只挂
next」与「caret 跨 minor 必失效」两条教训
- tests/market-manifest.spec.ts 的 peer 形状断言钉当前基线 tuple
- dsh.plugin.json engines.dsh → >=0.2.0-rc.1;SIDEBAR_SERVICE_VERSION → 0.24.0
- README/README_EN、CHANGELOG/CHANGELOG_EN、AGENTS.md(§2 钉版句 + §3 改为
「DSH 版本适配要点」并新增 §3.0 当前基线,0.1.7 内容降为历史分节)、
docs/external-plugin-guide.md 全部同步
验证:pnpm peers check 仅剩上游 better-locale 的 5 条 unmet(非本插件 peer);
typecheck / lint / test(136 文件 1484 通过 9 跳过)/ build 全绿;
DSH_CMD='npx -y --package @deepseek-ai/dsh@0.2.0-rc.1 dsh' pnpm test:mount = 7/7;
pnpm test:mount:aggregate 通过(聚合双挂载退让)
2026-09-28 21:21:45 +08:00
Menghuan1918
5c95002641
perf(sidebar): fs.tree 22.8ms→3.8ms + 删除工作区路径检测(放开权限)+ 树展开状态按会话
...
用户实测反馈:
1) `/sidebar/api/fs.tree` 性能极差 —— 先测后改(10k 条目目录、热缓存、中位数):
- 冷调用 cap=1000:22.76ms → **3.77ms**;TTL 内重复:≈23ms → **0.000ms**
- 改法:opendir for-await → readdir(withFileTypes) 一次取回;只为 cap 条建行
(slice + 定长数组);路径用字符串拼接而非 path.join;排序弃 localeCompare
(14.6ms/10k → 0.35ms)改小写比较 + 原名码点兜底;新增 1.5s 目录级缓存
(键 绝对路径\0cap,上限 512),由 fs.write/rename/remove/mkdir/upload 与
fs-watch 的变更通知显式失效
- 契约逐字不变;新增 tests/fs-tree.spec.ts 6 例 + fs-watch 失效用例(判别性验证)
2) 删除工作区路径检测(默认不检测、放开权限):
- path-security 变纯词法解析(realpath/包含性判定删除)、fs-operations 去 fence
分支、所有 fs 路由不再读 fence、403 分支消失、config 删 workspaceFence 字段
(schemastery 容忍未知键,旧 profile 不会加载失败)、settings 开关删除
- ⚠️ 安全影响:插件 fs 路由(tree/read/write/rename/remove/mkdir/媒体/HTML/
upload/archive)现在可读写宿主用户可访问的任意路径,只受 OS 权限约束;
指南 §8.1 已加醒目声明
- 死代码清理:FenceErrorNotice 组件 + EditorHost 分支 + 4 个词条(settingsFence*、
fenceErrorReason、fenceDisableAction)+ isOutsideWorkspace* 助手 + TreePanel 的
store prop + 相关 CSS 块
3) 批量列举路由 `fs.trees`(单层失败只在该层带 error)+ 客户端批量加载:
挂载/刷新时的 N+1 请求变为 1 个(8 个展开目录:9 → 1,探针断言)
refreshTick 不再先清缓存(旧行保留到新答案;失败保留旧行 + warn 提示)
4) 修复「关闭文件后返回文件树,展开状态被重置」:
原生承载面的展开集合原来存在每个 tab 的记录里(drop 即丢),改为**每会话状态**
的投影(ensure 从会话态读、toggleExpanded 写回会话态、registerNativeSurface 用
attachStore 订阅);同一会话多 tab 共享、不同会话隔离;revealed 保持 per-tab
验证:typecheck / lint / test(136 文件 / 1484 通过 / 9 跳过)/ build 全绿;
DSH_CMD='npx -y --package @deepseek-ai/dsh@0.1.7-rc.1 dsh' pnpm test:mount 7/7 通过;
版本镜像同步(dsh.plugin.json + SIDEBAR_SERVICE_VERSION)
2026-09-28 20:37:56 +08:00
Menghuan1918
f29743f03f
chore(release): v0.23.0 —— 文件页/文件变动页重构、菜单层级与性能、ZIP 进度、修复在侧边打开
...
本地安装需要与已发布的 0.22.0 区分(同一路径的 tarball 会被 pnpm 复用旧解析),
故把版本抬到 0.23.0;正式发版流程(tag → release.yml)不受影响。
2026-09-28 20:12:48 +08:00
Menghuan1918
ee1fe05067
feat(sidebar): 菜单层级/性能 + 选中条吸底 + 打包进度 + 修复「在侧边打开」
...
用户实测反馈 5 条:
1) 文件列表性能 / 右键菜单不再刷屏(先测量后改,探针 tests/file-tree-menu-perf.spec.tsx)
- 宿主应用列表按路径缓存:N 次打开菜单只请求 1 次(原每次 1 次 + Loading 帧)
- 行上的 git 数据改为原始值(tone/letter):共享 store 每次轮询重建对象不再触达行
(探针:开窗 folderIcons 4 → 0;root 行也 memo 化)
- 菜单开关不触发目录重列(fsTree=0);实测「菜单打开期间暂停轮询」会让变更行瞬时
掉色并多两次重渲染,故按测量结果放弃该做法(数字与理由写进探针注释)
2) 「已选择 N 项」条移到底部:滚动容器最后一个内容子节点 + sticky bottom(不遮最后
一行),窄栏 flex-wrap 换行不出横向滚动条
3) 菜单层级重构:一级只留默认动作(宿主默认应用 / 打开方式 ▸ / 在文件管理器中显示 /
新 Tab / 在侧边打开 / 下载 / 压缩并下载 / 复制路径 / 重命名 / 删除;目录行另有
新建文件夹、上传到此处),应用列表整体收进「打开方式」子菜单;宿主探测到本机关联
应用时默认不显示插件自研 open-with 项目,新增设置开关 openWithPluginTargets
(editor descriptor 的 pluginToggles)可强制并存;宿主不可用时插件项目照旧
4) 压缩并下载显示进度:宿主改为可观测任务(archive.build / archive.status /
/sidebar/archive?id=,4 并发 + 5 分钟 TTL + sessionId 绑定,buildZip 逐条目
onProgress),客户端轮询 250ms 显示「正在打包 done/total · N%」,ready 后 blob 下载,
失败进 zipFailed
5) 修复「在侧边打开没有效果」:根因是它只写插件底部工作台(原生右侧栏的 tab 不在
bottomSplits 里),现按承载面分流 —— 原生 tab 走 service.openTab(target:'side') →
宿主 openResource(preferNewPane, revealIfOpened:false) 真正分栏;底部工作台行为不变
(接入 API 变更已同步 docs/external-plugin-guide.md)
验证:typecheck / lint / test(135 文件 1461 通过)/ build 全绿;
DSH_CMD='npx -y --package @deepseek-ai/dsh@0.1.7-rc.1 dsh' pnpm test:mount 7/7 通过;
新增/更新测试:menu-perf(3)、archive(10)、open-in-app(18)、open-with(10)、multiselect(9)、
zip(37)、service(64)、editor-host(11)、builtins(23)、locales(20)
2026-09-28 20:11:46 +08:00
Menghuan1918
13d4bae321
fix(sidebar): 二轮独立验证的 9 项缺陷 + 目录级暂存
...
verifier 二轮报告(F1–F9)全部修复,每条都有「临时回退即变红」的判别性验证:
- F1【高】中文等非 latin1 下载名 → 真实宿主 500:content-disposition 改用
RFC 5987(ASCII 回退 + filename*=UTF-8'');补真 node:http 用例与根因对照断言
- F2【中】多选同名文件归档重名(解压互相覆盖):冲突项逐级上溯父目录消歧
- F3【中低】maxBytes 在读完之后才判定;budget<=0 的 0 字节 FIFO 会永久阻塞:
改为先 stat、读取前拒绝(FIFO 探针验证)
- F4【中低】SSH 模式 + 宿主不可用时 reveal 整条消失:保留 kind==='reveal' 目标
- F5【低】图钉嵌套交互语义非法且键盘不可达:改为诚实的鼠标热区,键盘入口归设置面板
- F6【低】变更树空闲 tick 全量重渲染:行 memo + 恒定 props + 内容键派生 +
共享 store 的 sameStatus 保住快照身份
- F7【低】排序随运行时 locale 漂移:显式 'en' collation + 码点兜底
- F8【低】POSIX 文件名的反斜杠被当成层级:不再替换
- F9【低】打包中重复点击静默、无反馈:busy 行(role=status)+ in-flight 守卫
- 新增:目录行「暂存/取消暂存该目录」(git pathspec 语义,不触发折叠)
验证:typecheck / lint / test(134 文件 1441 通过)/ build 全绿;
DSH_CMD='npx -y --package @deepseek-ai/dsh@0.1.7-rc.1 dsh' pnpm test:mount 7/7 通过
2026-09-28 18:20:08 +08:00
Menghuan1918
b011be1e98
feat(sidebar): 打开方式双源并存 + 多选压缩下载 + 文件变动层级树
...
用户追加三条需求,全部落地:
1) 打开方式 = 宿主探测应用 + 插件自研 open-with(并存)
- 逐字恢复 src/client/open-with.ts / open-with-settings.tsx / plugin-settings.ts /
src/open-external.ts / open.external 路由 / api.openExternal / editor descriptor
的 settings.render,以及 20 个 openWith* 词条(19 份词典从 main 取回原文)
- 恢复 menu-flip.ts + layout.css 子菜单翻转规则(子菜单回来了)
- FileTree 菜单段(无标题行):宿主行 → 分隔线 → 插件 pinned + 「在应用中打开 >」
子菜单(图钉 / SSH 后缀原样)→ 分隔线 → 宿主 reveal;宿主可用时过滤插件
explorer 目标,宿主不可用时插件行照旧(SSH 远端场景保持可用)
- 死键清理:菜单去掉标题行后 openInApp 词条无引用,已从 21 份词典删除
2) 文件页多选右键「压缩并打包下载」
- 新增 src/zip.ts(自研 ZIP:方法 0/8 按收益二选一、UTF-8 bit 11、目录条目、
自实现 CRC32、无第三方依赖)+ src/archive-route.ts(名净化 + 递归收集)+
GET /sidebar/archive(同一道 workspace fence、目录递归跳过符号链接、
10000 条目 / 256 MiB 上限)+ api.archiveUrl
- FileTree:多选 ≥2 项或单选目录时出现;fetch → blob → objectURL 下载,
路由错误(超限 / fence / 非 GET)以 zipFailed 显示在错误条
- 修掉真实缺陷:central directory 只写 MS-DOS 位而 version-made-by 声称 Unix,
Info-ZIP 会把每个文件解成 mode 000;改为 Unix 语义(0o100644 * 0x10000,
<< 16 会溢出 int32)。系统 unzip 复验:mode 644/755、unzip -t 无错
3) 文件变动页层级树 + 视觉打磨
- 新增 src/client/changes/change-tree.ts:单子目录链压缩成一行、目录先于文件、
大小写不敏感排序、文件带 GitFileStatus、目录带下级变更数
- GitLens 两组各自渲染树:折叠状态按「组+路径」独立、默认展开;分组头吸顶 +
计数胶囊;Stage all/Unstage all 改为带 aria-label 的 IconButton;选中 =
interactive-bg-active + 2px 内嵌强调条;12px/级缩进 + l1 参考线;
历史行 hash 徽标 / ref 胶囊 / 作者·时间右对齐
验证:typecheck / lint / test(134 文件 1422 通过)/ build 全绿;
DSH_CMD='npx -y --package @deepseek-ai/dsh@0.1.7-rc.1 dsh' pnpm test:mount 7/7 通过;
真实宿主截图确认三条需求(多选+双源菜单+zip 项、变动页树形层级)
2026-09-28 18:08:21 +08:00
Atlas Zeng
9b5834f74a
Merge pull request #787 from omdsh-dev/chore/release-0.22.1
...
chore(release): v0.22.1——修复 files 接管 id 孤儿化与 macOS 拖拽失效
v0.22.1
2026-09-28 11:35:31 +08:00
Menghuan1918
a18e0f000d
docs(release): 修正 v0.22.1 条目里的测试计数与「3/3」措辞(独立 review 发现)
...
- 单测计数:`122 files / 1292 passed / 9 skipped` → **1293**。1292 是 #785 当时的数字,
本 commit 自己的 `make check` 两次都报 1293(`tests/` 与 main 逐字相同,122 个 spec +
`it.each` 展开 = 1293)。涉及 CHANGELOG.md / CHANGELOG_EN.md / README.md / README_EN.md
与事故文档。
- 「3/3 红 / 3/3 绿」措辞改为「连续 3 次运行全红 / 全绿」并注明该 lane 里只有 1 个用例、
是重复跑三次——原措辞会被读成「3 个用例各红一次」。涉及上述四份发布文档 + 事故文档
+ AGENTS.md §2(同一句话在那边也有)。
- 其余 review 结论均已满足:版本三处锁步 + 两个守护用例绿、无遗留 0.22.0 引用、
zh/en 段落一一对应、「最近更新」保持两条并把指针下移为 v0.21.1 → v0.12.3、
release.yml 的 tag 校验与 `latest` dist-tag 都能过、lockfile 无需改动。
2026-09-28 11:30:29 +08:00
Menghuan1918
2e94b56c36
chore(release): v0.22.1——修复 files 接管 id 孤儿化与 macOS 拖拽失效
...
- package.json / dsh.plugin.json / SIDEBAR_SERVICE_VERSION → 0.22.1(三者锁步由
tests/service.spec.ts 与 tests/manifest-consistency.spec.ts 断言)
- README / README_EN:新增 v0.22.1 条目、同步三处徽章与 latest/支持线表格、
切回 npm 通道的示例版本号;「最近更新」保持两条(v0.22.1 + v0.22.0),
更早版本指针区间随之下移为 v0.21.1 → v0.12.3
- docs/external-plugin-guide.md:当前版本行 → v0.22.1
- CHANGELOG / CHANGELOG_EN:补 v0.22.1 条目(两个缺陷的根因链、真机证据、
修复要点与守卫清单)
支持线**不变**:仅 DSH 0.1.7-rc.1+(peer 下限 ^0.1.7-rc.1,CI 钉 0.1.7-rc.1);
0.21.1 / 0.22.0 用户直接升级;0.1.6-alpha.2 及更早仍固定 v0.19.1。
内容提要:① 修复客户端条目替换后 `dsh-better-sidebar:files` id 被孤儿化
(#777 + #785:清理循环跳过 FILES_KIND + 注册失败回滚已占用的 id 与槽位,
并新增部署级回归门 tests/e2e/native-reload.e2e.ts);② 修复 macOS 桌面版
窗口拖拽/双击缩放失效(#773 + #786:视口层用 initial !important 退出
app-region 计算,补齐放大视图,探针改用真实级联计算值)。
验证:make check 全绿(typecheck / lint / build / test 122 files 1293 passed
9 skipped / check:consumer-types);此外本地 pnpm test:mount 与
pnpm test:mount:aggregate 绿,npm 0.22.0 与修复版在 scratch profile 上的
红→绿对照见 PR #785 / #786。
2026-09-28 11:23:48 +08:00
Atlas Zeng
69f4349047
Merge pull request #786 from omdsh-dev/fix/desktop-app-region-rest
...
fix(desktop): 补齐 mermaid 放大视图的拖拽区退出 + 把 #772 的守卫换成真实级联探针
2026-09-28 11:22:22 +08:00
Atlas Zeng
e46250ae4d
Merge pull request #785 from omdsh-dev/fix/native-leak-guard-tests
...
fix(native): 钉牢 files 接管泄漏的守护断言 + 记录两条不变量
2026-09-28 11:17:35 +08:00
Menghuan1918
e7d2300cf8
fix(review): 按独立 review(Chromium 实测)修正 #786 的措辞、守卫与覆盖
...
reviewer 在本机跑 Chromium 逐条实测(同一批宿主规则 + 插件产物),结论:修复方向与形状正确
(`.mermaidModal` 预修复计算 `no-drag`、修复后 `none`;级联探针确实能把未修复产物判红),
但有几处措辞与守卫不到位。逐条处理:
1. **「app-region 会被继承」的说法在该引擎里不成立**:`[data-dsh-panel-host]` 不是 body
子元素(DOM 是 `body > [data-dsh-better-sidebar] > [data-dsh-panel-host]`),lane 用的
Chromium 不传播该属性(实测:`drag` 父元素里子元素读 `none`)。改写成「宿主是 body
子元素;在 Electron 里该值会传到它内部的面板层(#772 的 CDP 实测),lane 的引擎不传播,
所以面板层自己也声明同一条规则」——CSS 注释、指南 §12.1、探针注释三处同步。
2. **`regions.layer` 那条断言是真空断言**(修复前后都读 `none`):保留为回归钉子,但在
注释里明确标注它不具判别力、面板层的规则由 `panel-host-css.spec.ts` 钉住。
3. **给修复本身补行为级守护**:放大视图已经在同一 lane 里被真实打开过,于是在那里直接对
`[data-mermaid-modal]`(以及它的按钮)读计算值——断言用**页面里宿主自己的** darwin
规则(不再是探针复制的副本)。实测判别力:npm 0.22.0 上 `Received: "no-drag"`、修复版
`none`。
4. **「交互层不要加 initial」与放大视图的矛盾**:放大视图是**遮罩层例外**——模态语义下
只有其中控件必须保持 `no-drag`;残余代价(背景落在顶部拖拽带上时点背景会变拖窗)已写进
指南,避免后来者按字面判据「修」掉其中一边。
5. **`.selectionPopup` 的负向守卫可被选择器列表绕过**(reviewer 实测:`.selectionPopup,.x
{ initial !important }` 能通过):改成按**声明块**扫描——凡带 `-webkit-app-region:
initial` 的块,其选择器文本都不得出现 `selectionPopup`。
6. **补上 `none` 关键字的坑**:字面量 `none` 计算成 `no-drag`(是扣减值),只有 `initial`
/`unset`/`revert` 才是中性值——CSS 注释、指南与单元用例注释都已写明。
7. **未覆盖层给出结论**:`FileTree` 的 `.uploadDropChatHint` 是 body 直挂的装饰层,但只在
OS 文件拖拽悬停期间存在且 `pointer-events:none`,收益极小而**有意不处理**(写进指南,
不再让「覆盖清单」看起来是绝对集合)。
8. 顺带:`§12.2` 的同步集里 `tests/theme.spec.ts` 只守颜色(本轮无颜色改动),形状守护落在
已解析该样式表的 `tests/panel-host-css.spec.ts` 上——指南那句已按此表述。
验证:typecheck / lint 通过;panel-host-css 4 例通过;本地挂载 lane 7 passed(含新的放大
视图计算值断言);对 npm 0.22.0 的判别力实测:宿主探针红(`host` = `no-drag`)、放大视图
断言红(`modal` = `no-drag`),修复版全绿。
2026-09-28 11:17:03 +08:00
Menghuan1918
233201f7f8
fix(review): 按独立 review 结论修正 PR C 的注释、文档与用例保真度
...
独立 review(对照 606339f / 4099700 静态复核 + 日志逐行核对)提出的问题,逐条修正:
1. **补回被我自己抹掉的源码注释**:上次验证「未修复代码上 4/4 红」时用了
`git checkout 606339f -- src/client/native/index.ts`,随后 `git checkout HEAD --
<同一文件>` 把**尚未提交**的 `disposeSafely` 注释一起还原掉了 —— PR 描述里承诺的
「说明释放失败为何只走 console.error」因此在 diff 里根本不存在。已重新落盘。
2. **事故文档三处事实修正**:同一毫秒的 `already registered` 是 **7 条**(.339 一条 +
.340 六条,合计 burst 9 条),不是 6;验证段的「114 files / 1136 passed」是修复分支
(base 早于 #781)的数字,补上口径并给出合入 main 后的 122/1292;`index.ts:353` 标注
为 v0.22.0 行号(main 上因 #777 顺移)。
3. **撤回一处措辞过头**:「部分回滚分支从未被执行」→ 回收集合虽然进了、但 disposer
列表恒为空(释放动作未执行),改后能真正覆盖。
4. **e2e 门不再可能静默通过**:`test.skip(CLIENT_JS === undefined, …)` 改成硬失败——
这个门的价值就在于 harness 以后不再导出 DSH_HOME 时必须报错而不是变成 skip。
同时把「无 `[data-sidebar-right-unavailable]`」移到文件渲染断言**之后**(前者在空
pane 上恒真,不是真空但也没重量)。
5. **测试替身补齐保真度**:假注册表的 disposer 改为幂等(真宿主的 disposer 是幂等的
——cordis effect 二次释放返回同一个 task),避免「二次 release 又被记一笔」这种与
真实宿主不一致的行为被后续用例当成事实。
6. **AGENTS §2 的 HMR 机制加版本限定**:`mtime/ctime/size` 的 sha1 rev 是**钉住的宿主
0.1.7-rc.1** 的行为;DSH 源码树新版本改成只比 `mtime+size` 并对内容取 sha1,pin 上调
时该触发器必须同步复核(否则会红在替换断言上,而不是静默失效)。
验证:typecheck / lint 通过;pnpm test 122 files / 1292 passed / 9 skipped(重启前机器上有
两个 scratch dsh 服务时的 fs-watch 超时是负载抖动,单独跑 5/5 绿、清空负载后全量绿)。
2026-09-28 11:09:30 +08:00
Menghuan1918
b07c7116c8
fix(desktop): 补齐 mermaid 放大视图的拖拽区退出 + 把 #772 的守卫换成真实级联探针
...
#773 修掉了面板宿主层继承宿主 `body > :not(#root) { no-drag }` 导致的 macOS 拖拽
失效,但只覆盖了 `.mermaidModal` 之外的层——而放大视图是插件**第二个铺满视口的
body 直挂层**(`position:fixed; inset:0`,portal 到 body),打开期间会同样清空整窗
拖拽与 macOS 双击标题栏缩放。
- src/client/sidebar.module.css:`.mermaidModal` 加 `-webkit-app-region: initial
!important`(与面板宿主同一条契约),并在面板宿主那段注释里写明「哪些交互层
绝对不能加 initial」(`.selectionPopup` 是 `<button>`、FloatingWindow /
AnchoredPopover 自带指针拖拽,宿主 `:is(button, …)` 已给它们 no-drag;反过来
声明 `initial !important` 会让按下变成拖窗,重演 #103/#111)。
- tests/panel-host-css.spec.ts:新用例把形状钉在 Linux 的 `pnpm test` 里(宿主层
与面板层必须是 `initial !important`、`> *` 必须是 `no-drag`、`.mermaidModal`
同样退出、`.selectionPopup` 不得出现 `initial`)——没有 macOS runner,丢掉
`!important` 只能靠这里才不会静默复发。
- tests/e2e/mount.e2e.ts:把 #773 的**文本正则**断言换成**真实级联探针**——逐字
注入宿主两条 darwin 规则、翻转 `data-platform=darwin`,读取计算值并断言
`[data-window-drag]` 仍 `drag`、宿主层与面板层为 `none`、`[data-dsh-panel-host]
> *` 为 `no-drag`,随后还原。探针把 `[data-window-drag]` 放在 `#root` 内:直挂
body 的元素会被宿主那条 id 级规则本身命中(这正是问题机制)。
- docs/external-plugin-guide.md §12.1:按仓库规则同步这条皮肤契约(含交互弹层
的反例判据与守卫位置)。
实测(scratch profile + 真实 dsh web + Chromium):
- npm dsh-better-sidebar@0.22 .0:探针红,`host` 计算值 `no-drag`(正是线上症状)
- 本分支打包版:探针绿(`strip=drag` / `host=none` / `layer=none` / `child=no-drag`)
- 本地挂载 lane:7 passed(mount + perf,含新探针)
验证:typecheck / lint 通过;panel-host-css + theme 用例通过;新产物
`app-region:initial!important` 2 处(面板宿主 + mermaid 模态)、`app-region:no-drag` 2 处。
2026-09-28 11:04:52 +08:00
Atlas Zeng
0079ca83a3
Merge pull request #773 from jorgitin02/fix/macos-window-drag-panel-host
...
fix(desktop): stop panel host from blocking macOS window drag
2026-09-28 11:00:44 +08:00
Menghuan1918
85b09d888e
test(e2e): 页面内条目替换的部署级回归门(真机红→绿)
...
在 scratch profile 上用**已发布的 npm 0.22.0** 复现了线上那条报错链:页面内客户端
条目替换(宿主 HMR 的 500ms stat-poll 发现已安装 lib/client.js 的 rev 变化 →
teardown → 重新 import)期间,旧激活的 teardown 触发 sync(),让 files 接管在
inactive ctx 上重建 —— 控制台依次出现
native register files error: ... cannot create effect on inactive context
registerSlots ← registerFilesKind ← sync ← notify
native register files error: ... tab type id "dsh-better-sidebar:files" is already registered
register ← registerFilesKind ← sync ← notify
新用例 tests/e2e/native-reload.e2e.ts 把这条路径固化进挂载 lane(同一 lane 里
mount.e2e.ts 跑完后跑):utimesSync 已安装的 client bundle → 断言宿主元素被替换
(新激活)、无 native register … error、无诊断条、files 接管重新可用。
CLIENT_JS 从 e2e-mount.sh 已 export 的 DSH_HOME 推导,无需改脚本。
实测(同一台机器、同一份用例):
- npm dsh-better-sidebar@0.22 .0:3/3 红(每次都是上面那两条栈)
- 本地打包的修复版:3/3 绿
AGENTS.md §2 补一条说明该门与触发方式。
2026-09-28 11:00:23 +08:00
Menghuan1918
0b40f74ce8
fix(native): 钉牢 files 接管泄漏的守护断言 + 记录两条不变量
...
#777 已修掉根因(清理循环跳过 FILES_KIND、注册失败回滚已占用的 id),但它的两处
断言写在「活着的 id 集合」上——泄漏的 id 恰好构成同一个集合,未修复代码上同样
通过;且槽位失败判据按 key 命中,而一个描述符的两个槽共用一个 key,所以
registerSlots 的「部分回滚」分支从未被执行。
- tests/native-registration.spec.ts:断言改写到注册表的事件日志(孤儿 id 会让键
集合看起来完全正常);槽位失败判据改为 name::key,从而可以只让某个描述符的
第二个槽失败、真正走到部分回滚;补 reportFailure 的 phase 断言。实测:在
v0.22.0 源码上 4/4 红,在修复后的源码上 4/4 绿。
- src/client/native/index.ts:给 disposeSafely 补注释,说明释放失败只写
console.error、不弹诊断条的理由(两个调用点都在 teardown 路径上;真被占住的
id 会在下一次注册尝试里经 reportFailure 显式报出)。
- AGENTS.md:§3.4 第 9 条补上这两条不变量(含真机日志实证的链接),§6 把
native-registration.spec.ts 纳入关键测试守护。
- docs/plans/2026-09-28-native-files-takeover-reload-leak.md:事故/证据/否决方案
记录(含「吸收」方案为何被否)。
验证:pnpm typecheck / pnpm lint 通过;pnpm test 122 files / 1292 passed / 9 skipped。
2026-09-28 10:57:10 +08:00
Atlas Zeng
4099700bfa
Merge pull request #777 from yanzhaohui1999/fix/native-registration-leak-v2
...
fix(native): 注册失败的 tab 类型必须释放,否则 id 永久占用(插件重载后文件树变空态)
2026-09-28 10:54:48 +08:00
Menghuan1918
36fbc5ac7e
feat(sidebar): 文件页与文件变动页 UIUX 重构 + 全局组件抽取
...
文件页(FileTree/TreePanel)
- Ctrl/Cmd 多选 + Shift 按可见行序连选(Esc/点空白/右键收敛),批量条支持复制路径、批量删除(共享 ConfirmDialog + 顺序 fsRemove)
- Git 变更着色:行名按状态上色 + M/A/D/U 徽标,目录按 dirHasChanges 着色,非仓库静默降级(数据来自共享 git 状态存储)
- 新建文件夹:fs.mkdir 路由 + mkdirWorkspaceEntry + 内联输入行(Enter/Esc/blur/IME 守卫)
- 性能:FileRow/DirRow memo(含反向验证)、搜索 hidden 停车不再卸载树、level 拉取世代守卫 + AbortController、fs.tree truncated 提示、use-dir-watch 入参 memo
- 拖拽上传视觉 token 化(硬编码色清零);可见性下传后隐藏页签停止轮询
- 右键「打开方式」改为复用 DSH 自带 open-in-app(宿主探测的关联应用 + 文件管理器显示)
文件变动页(changes/diff)
- 36px 头(宿主 SegmentedControl)+ 单一 ChangeRow + SectionHeader 分组 + 吸底提交条单状态行 + 历史独立空态
- 修掉:双份空态、暂存失败 unhandled rejection、手动刷新被丢、仓库切换刷新两次、worktree 清单缺 repoRoot、工作树被自动切走、预览持旧快照、恢复高度未 clamp、session ops 无谓轮询
- DiffPane/DiffTab 共用 use-git-diff;修掉 DiffPane 的 untracked 预览从不渲染
全局组件与宿主接入
- 新增 src/client/ui(IconButton/Chip/SectionHeader/Notice/ConfirmDialog/StatusBadge + 共享 git 状态存储)
- 新增 src/client/open-in-app.ts(宿主 open-in-app 客户端适配),删除自研 open-with 全链路与 open.external 路由
- 客户端 inject 补 remote / remote.session:缺声明时 ctx.get('remote').session 会抛出并把整个面板打成错误条(真实挂载 lane 抓到)
- 词典:+25 键 / -20 openWith* / -noChanges,20 份同步
验证:typecheck / lint / test(126 文件 1322 通过)/ build 全绿;
DSH_CMD='npx -y --package @deepseek-ai/dsh@0.1.7-rc.1 dsh' pnpm test:mount 7/7 通过(含 tab sweep 与 perf lane)
2026-09-28 00:27:31 +08:00
Menghuan1918
606339f81e
chore(release): v0.22.0——任务管理页重做(工作流图)+ DSH 0.1.7 团队/后台任务数据面
...
版本号 bump 到 0.22.0(含 dsh.plugin.json 与 SIDEBAR_SERVICE_VERSION 两处镜像,
tests/manifest-consistency.spec.ts 与 tests/service.spec.ts 就是守这两处的),
README / README_EN 的版本徽章、支持线表格、npm 通道说明与「最近更新」段落同步,
CHANGELOG / CHANGELOG_EN 补 v0.22.0 条目正文。
支持线**不变**:仅 DSH 0.1.7-rc.1+(peer 下限 ^0.1.7-rc.1),0.21.1 用户可直接升级。
主内容是任务管理页从「子代理拓扑」重做为工作流图(图/树双视图、双段式节点卡、
主 Agent 同款合并活动行、扫光、两组折叠聚合、两个常驻浮动窗),以及随后按真机反馈
打磨的四轮修正;团队与后台任务两个数据面按 0.1.7 删掉的 Remote 方法/自建路由改写。
验证:typecheck / lint 通过;pnpm test 1288 passed / 9 skipped;build + pack 产出
dsh-better-sidebar-0.22.0.tgz。
v0.22.0
2026-09-27 22:33:57 +08:00
Atlas Zeng
11451e845f
Merge pull request #781 from omdsh-dev/feat/tasks-graph-polish
...
feat(tasks): 图模式打磨 + DSH 0.1.7 的团队/后台任务数据面适配(叠在 #680 上)
2026-09-27 22:25:37 +08:00
Menghuan1918
84b68e9216
feat(tasks): 任务窗内容填满高度可自然拉伸;聚合卡在成员多时报出 +N
...
用户两条优化:
1. 任务详细占满上下部分,不要留空(这样能自然拉伸)
2. 思考如何优化内容很多时的待命和完成的样式
第 1 条:描述区原本是 `max-height: 160px` 的滚动盒,窗口拉大只长空白。
FloatingWindow 新增 `bodyLayout: 'scroll' | 'fill'`(默认 scroll 不变,后台
任务输出窗仍按原样流动),fill 把 body 变成列容器、让调用方的子节点自己决定
谁吃余量;任务窗据此把余量全给描述区(编辑态给多行输入框,`flex: 1` 跟着窗
口长),头部行 / 元信息 / 负责人 / 提示行都 `flex: none`,不会跟着漂。
第 2 条:一队队友很多时,聚合卡只有一行名字却塞了十几个人,卡上看不出还有
多少。名称行现在写「前两个名字 + N」—— 用的是团队任务行已有的同一个 `+N`
约定,不是第二套;分组总数另有徽标和小条两处,所以 `+N` 只是尾巴而不是唯一
计数。图卡片与树行共用同一个 foldPreviews。
测试:新增 2 例(窗口声明 fill 布局、描述区在 body 内且编辑态换成多行框;
五个待命成员的聚合卡名称是 `m1 / m2 +3`);floating-window 既有 9 例回归通过。
pnpm test 1288 passed / 9 skipped,typecheck / lint 通过。
(cherry picked from commit 62651e731d6e5fd0378e2ecc504792cb2e3eb461)
2026-09-27 22:19:05 +08:00
Menghuan1918
11c2a16986
feat(tasks): 空闲与已完成分成两个聚合行;待命卡片补上自己的折叠按钮
...
用户两条反馈:
1. 空闲和已完成分开折叠合集
2. 空闲的无法折叠
第 2 条是纯疏漏:chevron 的出现条件写死在 `settled = done | error` 上,
「待命」的卡因此从来不画折叠按钮(跟折叠规则无关,规则早就允许手动收)。
现在 chevron 按「不在执行」(done | error | idle)出现,而 `settled` 仍只
表示完成/出错 —— 它管的是卡片该不该变淡,待命不是完成的工作。
第 1 条把上一轮那个「混合聚合」拆开:
- 一个父节点现在最多两行 —— `fold:<parent>`(已完成/出错)与
`fold:<parent>:idle`(待命成员);
- 各自的徽标说实话:完成行仍是「✓ N 已完成」,待命行是「N 个待命」;
完成行的条会额外报 `出错 N`(全是失败时只剩这一项),否则失败会藏在 ✓ 里;
- 待命行的条只写 `N 待命`(同组同状态,不重复计数);
- 阈值只作用于**自动**规则(≥3 待命成员才随页面级折叠一起收),手动 chevron
永远有效,两行互不牵连 —— 想扫掉待命的成员,不必连已完成的一起带走。
新增 tasksFoldIdleGroup ×20 词典;删掉上一轮的 hasIdle 与 foldBadgeCount
(分组后它们没有意义)。
测试:新增/改写 7 例 —— 三个待命成员收进 idle 行、两个保持可见、运行中成员
达标也不收、混合场景两行各归各的、手动折叠单个待命成员落进 idle 行、
待命卡确实带 chevron 且点后只剩聚合、聚合徽标说「N 个待命」。
pnpm test 1286 passed / 9 skipped,typecheck / lint 通过。
(cherry picked from commit 0c9c8abca85e8aeb54bb2e9fcaaeed0486a56c28)
2026-09-27 22:19:05 +08:00
Menghuan1918
c0ff3d1afd
feat(tasks): 空闲成员 ≥3 时自动收进聚合,聚合并如实报出状态配比
...
用户要求优化显示:「比如空闲时也折叠」。
在此之前,一个跑完一轮的 teammate(活体通道不报 running)映射成 idle,
而 idle 不在「已完成/出错」的可折叠集合里 —— 于是 8 人团队永远摆 8 张卡,
而同样「不在执行」的普通子代理却是 done、会折叠。同一事实两种显示,才是
这个痛点的根。
- 可折叠集合放宽到「不在执行」(done | idle | error);运行中/部署中永不折叠。
- 空闲**不无条件收**:按用户确认的阈值,一个父节点下空闲成员 ≥3 才随页面级
折叠规则一起收(FOLD_IDLE_MIN)。1–2 个待命成员就是这个团队的工作集,
而且它们的卡上会挂任务行,留着看;3 个以上才是「在扫名册」。
- 聚合行如实报账:聚合节点新增 doneCount/idleCount/errorCount/hasIdle,
小条写 `✓ N 已完成 · N 待命 · 出错 N`(为零的项省略,全已完成时与原先一样短),
徽标在**没有已完成项**时改说 `N 待命` —— 否则「✓ N 已完成」会把待命和出错
一起算成已完成,是撒谎。图卡片与树行共用 foldTally/foldBadgeCount。
- 手动折叠(卡片 chevron)不设阈值:那是读者点名要收的节点。
- i18n:新增 tasksFoldIdle ×20 词典。
测试:新增 6 例(阈值命中收 3 个空闲成员、2 个保持可见、运行中成员即使达标也不收、
混合聚合按状态计数、页面聚合行报「3 待命」且徽标不说已完成);pnpm test
1284 passed / 9 skipped,typecheck / lint 通过。
(cherry picked from commit 39d66ffb2e93eeb4095ec1cb2ac15933cce62742)
2026-09-27 22:19:05 +08:00
Menghuan1918
a7338bee1a
fix(tasks): 逐节点折叠按钮在聚合规则下失效(手动折叠不再共用自动折叠的守卫)
...
用户反馈「怎么折叠和怎么自动合并功能没了?我点击没反应」。
根因是折叠入口把两个触发条件塞进了同一组守卫:
if ((folded || foldedIds?.has(child.id)) && isLeaf && !child.current
&& child.team === undefined && (done || error))
`child.team === undefined` 是给**页面级自动聚合**准备的(teammate 是真实可续接
的工作者,不该被自动扫走),但它同样卡住了 `foldedIds` 这条**手动**路径。而卡片小条
的折叠 chevron 是按「已结算」画出来的——于是出现「按钮画出来了,点了没反应」这种
最差的失效形态:既没有折叠,也没有任何反馈。
改为按触发源分别守卫(`isAutoFoldable` = leaf + 非成员;`nodeFoldable` = 已结算 +
非当前会话),手动折叠只需后者;workflow run 成员两个触发都走 `nodeFoldable`。
测试:新增 4 例——手动折叠把「出错」的成员收进聚合、自动规则不动它、
运行中的成员即使用手动折叠也不被收起;pnpm test 1279 passed / 9 skipped,
typecheck / lint 通过。
(cherry picked from commit 3a47ddafe3c2d57f8997dc97f0118eb0530b114a)
2026-09-27 22:19:05 +08:00
Menghuan1918
d8bc6566df
feat(tasks): 适配 DSH 0.1.7 的 Agent Teams(读 projection + 写路由对接真实服务)
...
团队功能在 0.1.7 上整条失效:team-routes.ts 当初镜像的是 0.1.6 的 Remote 词汇
(remoteView / remoteCreateTask / remoteUpdateTask),而 0.1.7 把这三个方法删掉了,
读路径改到 Lead Session 的 `agentTeam` Session projection。真机 3080 复现:
teams.view 对带团队的会话返回 400 "membership.svc.remoteView is not a function",
于是 TeamBoard 从不渲染、节点富化与任务窗连带失效。
- 读:删掉 teams.view 与 5s 轮询,改读 SessionListState.projectionsBySession[root]
.values.agentTeam(与 subagentCatalog 同源,推送式);新增 client/team-projection.ts
做纯适配器,成员运行状态由 subagents.live 的 running 叠加、Lead 回退 session list
(官方 README 的 "overlays activity from Session status")。projection 缺席 =
这里没有团队,与旧的 {available:false}/{team:null} 合并成同一静默降级。
- 写:taskCreate/taskUpdate 改调 0.1.7 的 createTask/updateTask(返回已提交的 view,
拒绝改为抛 TeamError),TEAM_TASK_STALE_REVISION → 409 team-conflict,其余 → 400
team-error(wire 新增 team-conflict)。api.ts 的 writeTask 把失败信封还原成
{ok:false,code,message} —— 原先窗口永远走不到该分支(readEnvelope 是抛)。
- 任务窗:外壳换成上一轮的 FloatingWindow(可拖拽/可拉伸/只在关闭或 Esc 时消失),
动作行下沉到 shell 的 footer,长描述不再把动作推出视野。
- 真机抓到的两个单测抓不到的问题:
1. 队列中任务的「完成」被宿主状态机拒绝(pending → claim → in_progress →
complete → completed → reopen)→ 动作行跟随状态,pending 出「认领」;
2. 认领后 Tag 变「阻塞」—— ready 的语义只是「pending 且无未完成 blocker」,
对所有非 pending 任务都是 false → 抽出唯一规则 taskBlocked/taskStatusLabel/
taskTone/taskDotState,四处展示点全部改走它。
- i18n:新增 teamTaskClaim / taskWindowCreate / taskWindowDetail /
tasksStateProvisioning 词条 ×20 词典。
验证:typecheck / lint 通过;pnpm test 1276 passed / 9 skipped;
pnpm test:mount 7/7(真实 DSH 0.1.7-rc.2 挂载 + tab 全扫无崩溃)。
真机 3080(0.1.7-rc.1 + Agent Teams 实验层):看板从 projection 渲染、
队列任务「认领」→「完成」全链路写通(负责人 lead / 进行中 / 已完成)、
外部点击不关窗、Escape 关窗,截图见 docs/plans/2026-09-27-agent-teams-dsh-0.1.7-adaptation.md。
(cherry picked from commit dbc524e0b350c5d3564843f4776cd15d797506d8)
2026-09-27 22:19:05 +08:00
Menghuan1918
421fd3fde7
fix(tasks): 小条的状态词与活动行统一字体(修掉 1px 基线错位)
...
用户反馈「运行中和正在分析请求没对齐」。实测是字体度量差异,不是布局:
两者行盒完全一致(11px/14px、align-items: center 下同一位置),但 11px 下
sans 字族的 fontBoundingBox ascent/descent 是 11/2,mono 字族是 10/3 ——
基线低 1px。中文在 mono 栈里本来就走同一个 CJK 回退(PingFang SC),
mono 只改到句中的拉丁片段,等于半句等宽 + 整体低一像素。
修法:.barActivity 不再声明 font-family,两段文字共用小条自己的字族;
机器文本的等宽语气保留在 meta 行 / 后台任务行 / 终端输出井。
theme.spec 新增守护(.barActivity 不得声明 font-family)。
真机证据:真实运行中卡片的小条(3× DPR 截图 17-bar-real.png)两段同处一行,
两个 span 的 font-family 计算值完全相同;此前同一小条 3× 截图里蓝字明显偏低。
验证:typecheck / lint ✅ ;pnpm test 1257 passed / 9 skipped(新增 1 例)。
(cherry picked from commit 6816af76828a436eaf201205e385c1aa4f77dcd5)
2026-09-27 22:18:57 +08:00
Menghuan1918
7cce50c493
fix(tasks): 扫光改为整条完整扫过 + 折叠/展开按钮分向
...
用户反馈两条:
1) 扫光只有「部分」:第一版是 45% 宽的窄带 + background-position 位移,
亮带始终只覆盖小条的一部分(峰值 22.5%→77.5%,两端扫不到),看起来像
中间游走的一块光斑。改为与小条等宽的渐变带 + transform
translateX(-100%) → translateX(100%):光带从左外侧进入、中途覆盖整条、
再向右外侧离开,行程用条宽本身表达(任意条宽成立),末 1/3 周期停在
右侧外侧留白。theme.spec 新增守护钉住该形状(宽度 100%、transform 行程、
不再有 background-position/size 位移)。
2) 折叠按钮与展开按钮长得一样:三处控件原本共用向下箭头(控制条的折叠开关
更是无论折叠还是展开都画同一个清单图标)。现按动作方向区分——
卡片小条的逐节点按钮 = chevron up(收进聚合),聚合卡片 = chevron down
(展开),控制条开关随状态在两者之间切换(并复用同一个折叠图标)。
组件守护见 tasks-page.spec 的「draws COLLAPSE and EXPAND with different
glyphs」。
真机证据(3080,真实运行中的后台任务):242px 小条上每 90ms 采样 ::after 的
matrix 平移量得到 [-23,32,85,131,163,-139,-94,-46,9,64,114,152,179,188]
(左侧 -139 → 右侧 +188,跨度超过一个条宽,单调推进);三处 svg 比对
expandVsCollapse / clusterMatchesExpand / clusterFlips / clusterCollapseMatchesCard
全部为 true。
验证:typecheck / lint ✅ ;pnpm test 1256 passed / 9 skipped(新增 2 例)。
(cherry picked from commit 0bb8228e6a7acb4302d9a8a9881d2df04a285152)
2026-09-27 22:18:57 +08:00
Menghuan1918
d38fefe55d
feat(tasks): 任务输出常驻浮动窗 + 节点卡去竖线 + 手机设置
...
三件事一起落地(用户 brief),各自独立可验证:
1) 后台任务输出改为常驻浮动窗
- 新增 src/client/FloatingWindow.tsx + .module.css:可复用组件,标题栏(拖拽手柄 +
复制/关闭)、内容区(自滚动,长输出不再跑出视口)、可选底部行、三个拉伸柄
(右/下/右下)。生命周期与 AnchoredPopover 相反:外部点击、失焦、锚点离屏都不关,
只有关闭按钮与 Escape 结束;尺寸只在挂载时量一次(流式输出帧不会挪动读者摆好的窗);
拖拽保持整窗在视口内(放不下才退化到保留 48px 可达);视口变化时夹回。
- 手势复用既有范式:移动走 window 级 pointermove(同 AnchoredPopover),拉伸走
setPointerCapture + createFrameBatcher(同 EditorHost 的面板拉伸)。
- JobOutputPopoverContent → JobOutputWindow;顺带修掉「跟随最新」从不滚动的 bug
(原先滚的是 TerminalBlock 外面那个永不滚动的 div),并清掉随旧弹窗死掉的
.popPre / .jobPopPre 规则。节点/工作流详情与任务窗保持原样。
2) 节点卡统一
- 删除两条左侧竖条(层级条 .cardTop::before、当前会话条 .nodeCurrent::before);
层级改由上段极淡底色承担(7/5/3.5/2.5% → 9/7/5/3.5% 补偿对比度);
当前会话改为 2px accent 描边(「边框加粗高亮」)。
- 圆角 4px → 8px(与浮动窗同一家族);成员/工作流/聚合按用户选择保留类型区分。
- 2px 而非 1.5px:真机 recon 发现 Chromium 在 DPR 1 下把亚像素边框向下取整,
1.5px 的「加粗」完全看不出(实测 borderTopWidth: "1px")。几何不受影响
(border-box + min-height,卡片外框 247×134 与预算逐像素一致)。
3) 手机设置
- 两个新偏好 mobileNoAutoOpen / mobileDefaultTree(默认都开),落到 prefs-shared、
PrefsSchema(volatile 自动)、parsePrefs 校验与设置页新增的「手机」分组。
- 窄屏(沿用 768px 断点)时:新子代理与新后台任务都不再自动激活任务页;
任务页默认树状图(页内切换仍是临时覆盖)。宽屏或开关关掉后行为完全不变。
- 5 条词条 ×20 份词典;外部插件指南的 PrefsSchema 键清单同步。
验证:typecheck / lint ✅ ;pnpm test 1254 passed / 9 skipped(新增 14 例);
挂载 lane 7/7(真实 DSH 0.1.7-rc.2);3080 真机自测通过(长输出窗口内部滚动
5459px/449px、拖拽 424→304、拉伸 1008×540→918×480、外部点击不关、Escape 关、
卡片 8px/2px/无竖条、窄屏不自动弹出且默认树状图)。
(cherry picked from commit 7d9b428c6c34d28ad2d60c2086496eb533902273)
2026-09-27 22:18:57 +08:00
Menghuan1918
5ea2f2d6ec
docs(tasks): 工作图打磨的设计文档与真机验证证据;卡片细节两处修正
...
- 新增 docs/plans/2026-09-27-tasks-graph-polish.md:本轮问答结论、架构与文件、
关键设计(卡片两段 / 合并活动 / 扫光 / 折叠聚合 / ctx.jobs / 布局与窄栏)、
移植与丢弃清单、实施偏差记录、验证证据(含 3080 真机逐项目击记录与截图路径)、
未在真机复现的两项与已知取舍。
- 2026-09-14 图分支设计文档加「本轮打磨」小节指向新文档;README 任务页条目
与 AGENTS §1/§3.1#4 同步(后台任务改读宿主客户端 ctx.jobs,不再自建回放路由)。
- 卡片两处修正(真机截图暴露):
① 小条的钩子从 `data-state` 改为 `data-card-bar` —— 宿主自己的 primitive 也在
发 `data-state`(菜单分隔、编辑器等),同名属性让「卡片内恰好一条小条」的
断言与用户 CSS 都不可靠;
② 上段的 mono 行改由新的 `agentIdentity()` 产出(只讲「是谁」),根节点返回空
—— 原先复用 `agentMeta()` 会把状态词印两遍(徽章下方 + 小条),正是用户
反馈的「节点内信息太密」。可访问名继续用含状态的 `agentMeta()`。
验证:typecheck / lint 通过;pnpm test 1240 passed / 9 skipped;
挂载 lane 7/7(真实 DSH 0.1.7-rc.2);3080 真机自测通过(见文档表格)。
(cherry picked from commit 338a54820799c26ab91141e8d98c673b8d474610)
2026-09-27 22:18:49 +08:00
Menghuan1918
48294d336e
refactor(tasks): 后台任务改读宿主客户端 jobs 服务,删除自建三条路由
...
- 新增 src/client/jobs-client.ts:结构探测 ctx.jobs(watchRows / observe /
state / kill),引用计数的按会话 roster 订阅、只观测展开的那一行、
跨树去重(无主任务归到承载它的被观测会话,树外 owner 丢弃)。
- 抽屉与输出浮窗改读该服务:行来自推送 roster(状态 / 时长 / owner / 进度),
输出面换 TerminalBlock 显示宿主为观察者流的保留输出(gapBefore → 截断提示、
error → 失败提示),kill 走 jobs.kill(owner, jobId),两击确认不变。
- 自动激活(use-host-feeds)改骑同一条推送 roster;detectNewJob 增加
「观测起点时钟」参数,避免「页面打开时已在跑的任务」被当成新工作。
- 删除 src/jobs-routes.ts(+ tests/jobs-routes.spec.ts)、index.ts 的三条路由、
api.jobsList/jobOutput/jobKill 与 JobOutputResult、context-types 的
SidebarJobsService(换成 SidebarClientJobsService/SidebarJobsSnapshot/
SidebarObservedJob 镜像,SidebarJobView 补 owner/progress)、
页面里的 jobs.list 轮询与 collectTreeJobs。
- 三个 spec 改用假 ctx.jobs 服务(jobs-view 14 例 / 自动激活 12 例 /
页面 20 例):观测只在展开行、切换与关闭释放观测、watch 隐藏时不建立、
卸载时全部释放、无服务时不渲染任务面。
验证:typecheck / lint 通过;pnpm test 1240 passed / 9 skipped;pnpm build + pack 通过。
(cherry picked from commit 7d9b82e73190218f05910433ed520cb90e4d4ab2)
2026-09-27 22:18:35 +08:00
Menghuan1918
f584b67813
feat(tasks): 图节点改为双段式卡片 + 折叠聚合 + 窄栏可读性
...
图模式(主显示模式)换成新的卡片语言,树模式保持不变:
- 卡片 = 上段(类型徽章 + 相位徽标 + 名称两行 + mono 元信息 + 团队任务行)
+ 下段小条(状态点 + 状态词 + 主 Agent 同款合并活动 + 完成后的折叠 chevron)。
类型徽章用页面自己的词汇(主代理 / 子代理 / 成员 / 工作流 / ✓N 已完成)。
- 分组色(层级):按树深度取 4 档令牌色阶(color-mix 混 --dsw-alias-state-business-primary),
作用于左描边与上段极淡底色;相位徽标走 ink 色族,两套分组不撞色。
相位虚线框保留但改用同色极淡描边,卡片徽标承担「这是哪个阶段」。
- 执行态:小条 `data-running` + 从左到右扫光(1.5s,末 1/3 停顿,
prefers-reduced-motion 关闭);合并活动行来自宿主 chat 词条,缺失时回退插件文案。
- 折叠:已完成节点的 chevron 把该节点「收进已完成聚合」(模型新增 foldedIds,
与全局 folded 走同一组守卫:只在已结算叶子、非当前会话、非团队成员时生效);
聚合节点点击 = 全部展开(清空手动集 + 关闭全局折叠);控制条仍只管全局规则。
- 布局与窄栏(用户反馈 a–f):卡片高度预算按新行重算(徽章 + 两行标题 + 元信息 +
小条 = 103px,任务行 +18),宽度 176 → 190;fit 按内容包围盒双轴居中、
FIT_MAX_SCALE 1.15 → 1.30;缩放范围 0.4–2.0 并归一化 wheel deltaMode;
平移加边界夹取(至少 72px 内容留在视口内);空画布双击重新适配并恢复自动 fit;
连线改「垂直出线 stub + 贝塞尔」并加粗到 1.5px。
验证:typecheck / lint 通过;pnpm test 1253 passed / 9 skipped(含新增双段结构、
data-running、chevron → 聚合、聚合 → 全部展开、工作流相位徽标 5 例)。
(cherry picked from commit aee571e50beb5dc979995f0841cffd0a575f2173)
2026-09-27 22:18:35 +08:00
Menghuan1918
a454cfc9fe
refactor(tasks): 移植主 Agent 同款合并活动折叠(数据层)
...
把上一轮验证过的数据层搬到工作图基座上,图/树两种模式共用:
- 新增 src/process-activity.ts:宿主 ui-chat 的 process group 算法移植
(activity() 分类表逐条照抄、liveToolDetail 键优先级与 160 字截断、
counts 计数排序与并列规则、preparing 语义、按 user/reply 边界切范围)。
按本轮设计裁剪掉逐阶段列表(阶段改由徽标 + 颜色表达)。新增一条
偏差:最新范围为空(子代理刚回复完)时回退到上一个「做过事」的范围,
否则已结算卡片的小条只会显示「已完成分析」。
- chatT:从宿主 chat 命名空间读 message.stepProcess.* 措辞(方法调用 +
try/catch 兜底,key 未命中即回退),4 个回归用例钉住「不许解绑 bind」。
- subagents.live 载荷换新:SidebarChildLiveView { running?, text?, summary?,
lastEventTime? },报告树内每个子节点(含已结算)与拓扑根;删除
expand/stages 机制;childActivity → childLive(「不在 map 里 = 未运行」
的读法随旧协议一起作废)。
- tasks-model 消费新形状;LiveLine 与节点详情浮窗改显示合并活动措辞。
- 删除 src/subagent-activity.ts 与 tests/subagent-activity.spec.ts。
验证:typecheck / lint 通过;pnpm test 1252 passed / 9 skipped。
(cherry picked from commit 5e5284f214846b0c366048acbee459f3a7a79456)
2026-09-27 22:18:35 +08:00
Menghuan1918
2a39a0c8b2
chore: adapt the tasks/workflow/teams work to DSH 0.1.7-rc.1 (rebase onto v0.21.1)
...
Rebases the whole branch onto main's new 0.1.7-rc.1 baseline and lands the
adaptation the new host contract requires: the ui-primitives icon family rename
(Icon<Name><14|16> -> Icon<Name>Regular/Medium, with the 14px defaults pinned
back explicitly) and the StateDot redraw, the rewritten dsh-settings surface
(entry-id namespace, DSH schemastery with collected volatile returns,
configure auto:false), session format v4 (producer-owned source kind plus the
rewritten tool-result shape, parsers accepting both), the client snapshot move
to projectionsBySession.subagentCatalog with the jobs.list route behind it, the
^0.1.7-rc.1 peer floor with vendor and bare-import devDeps, the reduced chunk
set mirrored in all eight places, and the capability hand-backs (read-only
previews, terminal, browser).
Verified: typecheck and lint clean; 119 files / 1200 tests; build with no old
contract residue in the bundles; mount e2e 7/7; the tasks page still passes its
70-assertion real-browser contract.
2026-09-27 22:18:19 +08:00
Menghuan1918
b554665bde
feat(tasks-ui): readability pass, height-budget fix and leftover sweep
...
The native port is finished off with the readability work the earlier rounds
left open, plus the cleanup of everything the shadcn era or the older canvas
left behind.
- Geometry: node height is now composed from named parts (chrome, two title
lines, meta row) and per-node extras, so a teammate card that carries a task
line no longer gets clipped by the old fixed 68px budget; the layout spec
follows the new model and GRAPH_ROW_STRIDE stays exported for it.
- Readability: row rhythm (28-32px), three ink levels for title/meta/owner,
truncation with title hints, current-row and hover expressed as an accent bar
plus a hover fill (no shadows), phase frames and edges back on the l1/l2
hairlines, control cluster uniformly 28px, drawer durations on tabular
figures, kill action revealed on hover/focus without shifting the row, no
horizontal overflow at 360px.
- Task window: the markdown body is pulled onto the page scale (12px body,
12/13px headings, tightened list indent and paragraph spacing) while the
shared MarkdownText/markdownTextProps contract is untouched.
- Cleanup: dead stylesheet rules, unused TSX exports and helpers, stale
comments that still described the retired Variant-D canvas, zero-reference
i18n keys across the dictionaries, and the Tailwind/shadcn/Variant-D
narrative in the design doc, AGENTS.md and the plugin guide (kept as one
short "why it was rolled back" section).
Verified here: typecheck and lint clean; 133 files / 1413 tests; build with no
radix-ui or --tw- strings in lib/client.js (988.9 KiB); the 70-assertion
real-browser contract at 70/70 with the 20 reference screenshots regenerated;
mount e2e 7/7.
2026-09-27 22:18:19 +08:00
Menghuan1918
ae4280c70e
cleanup(tasks-ui): drop the dead rules the native port left behind
...
Removes the stylesheet rules nothing references any more (popPrimary, teamBtn,
teamOwnerSelect, teamForm, teamInput, treeInfo, teamMember, teamTaskStatus,
nodeTitle variants), keeping the page at the plugin's own scale: typecheck and
lint clean, 133 files / 1410 tests, and the 70-assertion real-browser contract
still passes at 70/70 with the 20 reference screenshots regenerated.
Note: the accompanying per-node height refactor for the task-line clipping bug
was reverted — it removed the exported GRAPH_ROW_STRIDE the layout spec depends
on and broke four layout tests, so it needs a proper round of its own.
2026-09-27 22:18:19 +08:00
Menghuan1918
a71d158f9a
revert(tasks-ui): drop the shadcn/Tailwind layer and return to the plugin's own UI system
...
shadcn's defaults are built for a standalone app: 14px body, 36px controls,
solid primary fills and elevation read as a foreign surface next to this
plugin's own tabs (files, changes, side chat, settings), which are 12/11/10px
type, 28px controls, hairline borders and flat panels. Retuning the layer did
not converge, so the layer goes.
- Removed: src/client/ui/** (21 vendored components), components.json,
scripts/ui-css.mjs, the Tailwind/PostCSS compile step in tsdown, and the deps
tailwindcss / @tailwindcss/postcss / postcss / radix-ui /
class-variance-authority / tailwind-merge. (diff and simple-icons stay: they
patch undeclared bare imports of the host primitives, unrelated to shadcn.)
- The seven page surfaces are back on the plugin's own base: *.module.css with
--dsw-* tokens plus the host primitives (Button/Menu/Modal/Pill/Tag/Switch/
Input/Tooltip/StateDot/MarkdownText). Behaviour, data-* hooks, aria labels,
i18n keys and the AnchoredPopover geometry/drag/dismiss contract are
unchanged; the non-styling fixes landed during the shadcn era (model id
dedupe, task-window CAS, drawer arming, popover dragging, the chunk packaging
glob) were re-applied and are covered by the existing specs.
- The tasks page returns to the core bundle: `tasks` left CHUNK_NAMES /
CHUNKS / ChunkName, src/client/chunks/tasks.tsx is gone and tabs.tsx imports
SubagentView directly.
- The reverted stylesheet was retuned to the plugin's measured vocabulary
(12/11/10px, 28px controls, border-l2 with border-l1 hairlines, hover fills,
no static shadows, --dsw-shadow-lv2/3 on floating layers only) and verified
against a 70-assertion real-browser contract; the harness's own two
measurement defects were fixed with a falsification test proving the
assertions still catch injected regressions (56/70, 14 FAIL).
- Tests: ui-foundation / ui-bundle / ui-shadows (the shadcn guards) deleted,
theme.spec scoped back to the plugin's own stylesheets, bundle-route and
manifest-consistency chunk lists back to four. Docs: AGENTS.md and the plugin
guide drop the Tailwind/shadcn guidance; the design doc marks those sections
superseded and records why the layer was removed.
Verified: typecheck/lint clean; 133 files / 1410 tests; core bundle 987.3 KiB
with no radix-ui/--tw-/tailwind strings and no client-tasks.js; mount e2e 7/7;
20 real-browser screenshots at 360/720 for graph, tree, board, task window,
drawer (including armed), both popovers and the 77-node fixture.
2026-09-27 22:18:19 +08:00
Menghuan1918
e500a3d2b9
style(tasks-ui): retune the page to the plugin's own visual language
...
Stock shadcn defaults are designed for a standalone app; next to this plugin's
other tabs (files, changes, side chat, settings) they read as foreign: 14px body
against 12px, 36px controls against 28px, #00000029 borders against the plugin's
10%/4% hairlines, solid primary badges against flat state tints, and elevation
where every other panel is flat.
Measured the plugin's own vocabulary from its CSS modules (12px body / 11px meta
/ 10px micro; 16-20px line heights; 28px controls; 6x8 and 6x10 paddings; 8/6/4
gaps; 6/8px radii; `border-l2` for 1px borders and `border-l1` for hairlines;
`--dsw-shadow-lv2/3` only on floating layers) and mapped the vendored set onto
it instead of editing every page:
- theme.css bridge: `--border`/`--input` -> `border-l2` (l4 was visibly darker
than every other tab), new `--border-subtle` -> `border-l1`, the type scale
remapped (text-xs 11px, text-sm 12px, text-base 13px, text-lg 14px), elevation
mapped to the plugin's tokens (static shadows none, md/lg -> --dsw-shadow-lv2
/lv3), and the state tints bridged.
- component defaults retuned to the same scale: button sizes 28/24/20px with
text-xs, card padding 12px with gap-3 and no shadow, input 28px, badge 18px
with 11px ink, empty at p-4, separators on the hairline token.
- badges: the default variant is the plugin's flat state tint
(bg-state-business-tertiary + state ink, the same recipe sidebar.module.css
uses for revealed rows) rather than a solid primary fill.
Guards updated with the reasoning inline: the border bridge expectations, a
`none` value being the plugin's way of saying "flat", and the skin-contract
check now derives local token names from the file instead of a hand-kept list.
Verified: typecheck/lint clean; 136 files / 1515 tests; build with the bundle
guards; mount e2e 7/7; mirror-page screenshots (real host stylesheet + real
components) re-shot at 360/720 for graph, tree, board and the 77-node fixture.
2026-09-27 22:18:19 +08:00
Menghuan1918
5deb5285da
refactor(tasks-ui): align the page with the latest shadcn/ui defaults
...
The previous round kept a hand-trimmed, shadow-less, 11-13px variant of the
component set. This replaces it with the registry's own defaults and the
registry's own composition primitives, keeping only the adaptations this host
actually requires.
Registry refresh (npx shadcn@latest add --overwrite): the whole vendored set is
back to upstream sources, plus label, field, input-group, item and button-group.
Re-applied adaptations (documented in the design doc):
- cn from ./utils and explicit ./x.tsx specifiers (the registry writes virtual
aliases this repo has no resolver for);
- host IconXxx instead of lucide (skin contract);
- no dark: variants (the DSH tokens already flip) and no palette literals;
- React.forwardRef on Button (the host is React 18, so radix Slot needs it);
- tw-animate-css animation utilities stripped: installing that dependency would
inject generic keyframes into a page we do not own.
Restored to stock: the full Button variant/size set, shadow-xs on outline,
transition-all, badge ghost/link.
Recomposition on the newest primitives (per-file, verified here):
- board: full Card composition, Item rows, ToggleGroup filter, dropdown items
grouped, Empty for the empty state;
- task window: Card composition, FieldGroup/Field with data-invalid validation,
ToggleGroup owner (default variant: the outline variant's hover and pressed
states measured identically, hiding the selection), destructive-armed delete,
FieldError for conflicts;
- popovers: both portal cards use the same Card composition, rows are Item;
- drawer/header: Item rows with ItemActions, Separator bands, Spinner, Empty;
- graph/tree: stock node recipe, outline buttons, cn() for conditional classes.
Two no-preflight traps found by rendering, not by types:
- stock Empty ships border-dashed without a width, so the UA's 3px medium dashed
frame wrapped the whole page: border-0 on that Empty;
- <Spinner size={12}/> stayed type-clean after the refresh (size is a valid span
attribute) while the glyph silently rendered at size-4: className="size-3".
Verified: typecheck/lint clean; 136 files / 1515 tests; build with the core and
chunk bundle guards (core 836.3 KiB, chunk 734.7 KiB); mount e2e 7/7; and the
real-host-stylesheet mirror page re-shot for graph, tree, board, task window and
the 77-node stress fixture at 360 and 720.
2026-09-27 22:18:19 +08:00