diff --git a/docs/plans/2026-09-14-tasks-graph-workflow-teams-design.md b/docs/plans/2026-09-14-tasks-graph-workflow-teams-design.md index f491305..8ecd9ed 100644 --- a/docs/plans/2026-09-14-tasks-graph-workflow-teams-design.md +++ b/docs/plans/2026-09-14-tasks-graph-workflow-teams-design.md @@ -4,7 +4,7 @@ ## 背景与目标 -DSH 0.1.5-rc.2 引入两个新的可观测面:**workflow**(`dsh-tool-workflow` 的 run/agent 生命周期事件)与 **Agent Teams**(实验层,`ctx.agentTeams` 的共享任务板)。任务管理页(原「子代理拓扑」)系统性地接纳两者,并按用户确认的「简洁后现代主义」方向重构为 **Variant D 工作流图**:分层节点 + 贝塞尔连线、拖拽平移、滚轮缩放、右下角控制条、已完成节点折叠聚合、点击浮窗取代页内 dock。 +DSH 0.1.5-rc.2 引入两个新的可观测面:**workflow**(`dsh-tool-workflow` 的 run/agent 生命周期事件)与 **Agent Teams**(实验层,`ctx.agentTeams` 的共享任务板)。任务管理页(原「子代理拓扑」)系统性地接纳两者,并按用户确认的「简洁后现代主义」方向重构为**工作流图**:分层节点 + 贝塞尔连线、拖拽平移、滚轮缩放、右下角控制条、已完成节点折叠聚合、点击浮窗取代页内 dock。 用户确认的关键交互决策(问答摘要): @@ -12,7 +12,7 @@ DSH 0.1.5-rc.2 引入两个新的可观测面:**workflow**(`dsh-tool-workflo 2. 节点点击 = 跳转转录;ⓘ = 详情浮窗。 3. 后台任务输出 = 锚定浮窗(替换页内底部 dock)。 4. 自动折叠**只**作用于后台任务抽屉,阈值 8 个代理;图节点的折叠是「已完成」语义的折叠聚合,点击展开、控制条可再折叠。 -5. 图/树切换按钮在**两种模式下都可用**(mockup 的 toggle 藏在画布容器内、树模式下无法切回——真实实现把控制条移出滚动面)。 +5. 图/树切换按钮在**两种模式下都可用**(早期设计稿把 toggle 藏在画布容器内、树模式下无法切回——真实实现把控制条移出滚动面)。 6. 默认视图由设置 select 决定(默认工作流图),页内切换为临时态。 7. 任务板 v1 只做基础操作(完成/重开/删除/改派/新建/编辑,CAS)。 @@ -69,7 +69,7 @@ client 半(src/client/) - **workflow 无事件 = 空列表不是错误**:旧会话/无 workflow 会话静默为空(jobs 镜像同款语义)。 - **fold 规则**:per-parent 的「已完成/出错的**叶子** agent」折叠为一个聚合节点;当前会话、teammate、有子节点的、run 节点**永不折叠**(折叠父节点会藏住活跃分支)。 - **树/图同一模型**:fold 状态、团队富化、run 重挂两种模式共享——不会视觉漂移。 -- **控制条移出滚动面**:图模式的缩放按钮与图/树切换都在视图容器级(绝对定位右下),树模式下缩放按钮不渲染但切换在(mockup bug 的教训,有测试守护)。 +- **控制条移出滚动面**:图模式的缩放按钮与图/树切换都在视图容器级(绝对定位右下),树模式下缩放按钮不渲染但切换在(早期实现把它放进滚动面、树模式下切不回去——有测试守护)。 - **页内视图切换是临时态**,默认视图走 `tasksViewMode` pref(schemastery `z.union([z.const('graph'), z.const('tree')])`——schemastery 无 `z.enum`)。 - **AnchoredPopover 不复用 primitives 的 HoverCard**:浮窗需要持久交互(任务板表单、输出滚动),HoverCard 是悬停语义;关闭契约(外部 mousedown / Escape / anchor 离屏的 IntersectionObserver)沿用 selection-popup 已验证的模式。 - **主题硬阴影用 `color-mix(in srgb, var(--dsw-alias-border-l1) 55%, transparent)`**:后现代硬投影但颜色全部出自令牌(theme.spec 只守 `color:`,皮肤契约的精神照旧满足)。 @@ -90,17 +90,17 @@ client 半(src/client/) | 反馈 | 根因 | 修法 | |---|---|---| -| 「按钮和文本的颜色不对,不够后现代」 | 新 CSS **17 处裸用 `var(--dsw-alias-accent)`——该令牌在 DSH 主题里不存在**(旧文件的用法都带 fallback 才没暴露),声明被浏览器整条丢弃;容器边框用的 `border-l1` 只有 4% 黑,几乎不可见 | accent → `--dsw-alias-state-business-primary`;容器边 → `--dsw-alias-border-l4`(16%);整体改回 mockup 语言:ink 边框、3px 硬投影、mono 微型字 + 字距大写标签、点阵画布、横向缩放条 | +| 「按钮和文本的颜色不对,不够后现代」 | 新 CSS **17 处裸用 `var(--dsw-alias-accent)`——该令牌在 DSH 主题里不存在**(旧文件的用法都带 fallback 才没暴露),声明被浏览器整条丢弃;容器边框用的 `border-l1` 只有 4% 黑,几乎不可见 | accent → `--dsw-alias-state-business-primary`;容器边 → `--dsw-alias-border-l4`(16%);整体回到设计稿语言:ink 边框、3px 硬投影、mono 微型字 + 字距大写标签、点阵画布、横向缩放条 | | 「点 ⓘ 没反应 / 图里点不动(树能点)」 | 画布 `pointerdown` 里对容器 `setPointerCapture`,捕获把派生 click 重定向到容器,节点永远收不到点击(jsdom 不模拟捕获语义,所以单测全绿——**只有真实浏览器能暴露**) | 去掉 capture,pan 仅从背景起手(`closest('[data-graph-node]'/'[data-graph-controls]')` 直接返回),监听挂 window | | 「图很小 / 不在中间 / 任务板没显示」 | fit 在容器为 0 尺寸时静默放弃且不再重试;只居中横轴、上限 1.0;窄面板里 5 个兄弟节点挤成 770px 宽 → 缩到 35% | ResizeObserver + 首次非零尺寸补 fit、双轴居中、`FIT_MIN_SCALE=0.78` 可读性下限;**按容器宽度求解排布**(`layoutTasksGraphForWidth`:先取仍满足可读性预算的最宽排布,只有窄到 ≤1 列才允许 20% 横向溢出);任务板改为**常驻可见条**(不再藏在 chip 后) | | 「卡片信息过多过杂,都被省略看不见」 | 卡片同时塞 displayTitle + 模式 + 状态 + 模型 + live 文本,132px 宽(窄面板的目标宽度)下全部省略号 | 卡片只留三层:标题(1 行)/ mono 元信息(模式或模型 · 状态)/ live 行(仅运行中);其余(会话标题、team 角色、模型全名、最新文本、跳转)进 ⓘ 浮窗 | -| 「非常窄,非常挤」 | 设计按宽画布做,未以原生右侧栏窄宽为目标 | 度量全部改按 mockup 的 360×660 基准(卡片 132×46、行距 112);行高/间距/字号显式声明(宿主 body 行高曾把行撑高);`user-select: none` 防拖拽选中文本 | +| 「非常窄,非常挤」 | 设计按宽画布做,未以原生右侧栏窄宽为目标 | 度量全部改按窄栏基准(卡片 132×46、行距 112);行高/间距/字号显式声明(宿主 body 行高曾把行撑高);`user-select: none` 防拖拽选中文本 | 回归面:`tests/tasks-page.spec.tsx` 增 3 例(背景 pointerdown 后节点仍可激活、节点上的手势绝不启动 pan、团队任务板无需点击即常驻可见);`tests/tasks-graph-layout.spec.ts` 重写 9 例(band 换行、换行 band 不得压到兄弟子树行、宽度求解两段式、运行时预留 live 行)。 ### 本地可视化自检 harness(未入库,`tmp-visual/`,git-excluded) -真实浏览器里的组件级回归无法靠 jsdom 覆盖(点击捕获、fit/居中、主题令牌解析都是浏览器行为)。harness 用 esbuild 把**真实组件** + mockup 形状的 fixture(走 `buildTasksModel`,因此折叠/重挂/富化都真实生效)打包进一个页面,注入从 `dsh-client-ui-theme` 抽出的令牌 CSS,`@deepseek-ai/dsh-client-ui-primitives` 别名到轻量桩(避免把 katex/shiki 资源拖进截图包),再由 Playwright 在 360px / 720px 两档宽度截图并断言:节点点击回调、ⓘ 回调、背景拖拽平移量。本次返工的四条反馈里有三条正是它先复现、修完再确认的。 +真实浏览器里的组件级回归无法靠 jsdom 覆盖(点击捕获、fit/居中、主题令牌解析都是浏览器行为)。harness 用 esbuild 把**真实组件** + 与 `buildTasksModel` 同形状的 fixture(走同一个模型,因此折叠/重挂/富化都真实生效)打包进一个页面,注入从 `dsh-client-ui-theme` 抽出的令牌 CSS,`@deepseek-ai/dsh-client-ui-primitives` 别名到轻量桩(避免把 katex/shiki 资源拖进截图包),再由 Playwright 在 360px / 720px 两档宽度截图并断言:节点点击回调、ⓘ 回调、背景拖拽平移量。本次返工的四条反馈里有三条正是它先复现、修完再确认的。 ## 第二轮返工(2026-09-14 深夜,13 条反馈) @@ -132,9 +132,10 @@ i18n:本轮新增 19 条文案,zh/en/ja + 18 份第三语言词典同步(` |---|---| | `TaskPopover` | 任务板行、节点任务行、节点详情任务清单、新建按钮(4 处) | | `MultilineField` | 任务描述编辑(宿主 primitives 无多行输入,故自建) | -| `TaskCreateButton` | 任务板 / 其它入口共用同一外观 | | `AgentGlyph` / `WorkflowGlyph` / `FoldGlyph` / `TaskLine` | 图与树两种模式共用 | +> **回退后修订**:上表与上一行提到的 `TaskCreateButton` 已删除——它唯一的调用方就是任务板,包一层没有收益;任务板的「新建」现在直接是宿主 outline `Button` + `IconPlusOutline16`(同一文案键 `teamTaskCreate`)。`TaskWindow` / `TaskPopover` / `MultilineField` / `OwnerPicker` 不变。 + ## 验证结果(2026-09-14) PR:[#680](https://github.com/omdsh-dev/DSH-better-sidebar/pull/680)(分支 `feat/tasks-graph-workflow-teams`)。 @@ -147,264 +148,13 @@ PR:[#680](https://github.com/omdsh-dev/DSH-better-sidebar/pull/680)(分支 ` 未在本机自动化验证、留给用户实机确认的一项:3384 桌面应用**重启后**的 UI 级复看(新 bundle 已装进 `~/.dsh/profiles/web`,与仓库构建产物 SHA-256 一致)。 -## shadcn/ui 迁移(2026-09-17,视觉基座替换)—— 已废弃 - -> **已废弃(2026-09-21 整体回退)**:本节及其后全部子节(依赖与实际版本 / Tailwind 接入方式 / 令牌映射表 / vendored 组件清单 / 阴影策略 / 体积与 mount 结果 / 真机排障 / stock 风格回调 / 升级路径与本地适配清单 / 页面重组)记录的是 2026-09-17–09-21 期间任务页的 shadcn/ui 视觉基座。该基座已整体回退到插件自有体系,回退根因见文末「回退:任务页回到插件自有体系(2026-09-21,shadcn 层废弃)」。保留全文只为留下排障现场与决策证据——**其中描述的接入方式不再是本仓库或消费插件的建议做法**。 - -三轮返工把**行为**收敛到位(统一的详情窗口、常驻任务板、可拖动浮窗),但**视觉基座**仍是自建: - -- 每张卡片 / 每个节点 / 每行都是一次手写样式,同一种「卡片」在四个文件里有四份近似声明; -- 卡片自带 `color-mix()` 硬投影与描边,节点一多**满屏阴影相互叠加**,正是「辣眼睛」的根因(阴影是层级手段,被当成了装饰); -- 控件形态靠逐处微调对齐,hover / focus-visible / disabled 三态在不同文件里覆盖程度不一。 - -处置不是再打磨一轮自建样式,而是**换基座**:把 shadcn/ui 的组件源码 vendoring 进 `src/client/ui/`,样式统一由 Tailwind v4 工具类产出,颜色统一走 shadcn 语义令牌 → `--dsw-*` 的桥接,**静态面板零阴影**(层级改由 1px hairline + 表面阶梯承载)。行为语义、稳定钩子、i18n 全部不变,因此这次迁移对上层是不可见的。 - -### 依赖与实际版本 - -| 包 | 版本 | 归属 | 作用 | -|---|---|---|---| -| `radix-ui` | `^1.6.7` | dependencies | vendored 组件的无样式原语(聚合包,不是 `@radix-ui/react-*` 一族) | -| `class-variance-authority` | `^0.7.1` | dependencies | `buttonVariants` / `badgeVariants` / `toggleVariants` 的变体表 | -| `clsx` | `^2.1.1` | dependencies | `cn()` 的条件拼装 | -| `tailwind-merge` | `^3.7.0` | dependencies | `cn()` 的同族工具类去重(调用方的 `px-4` 胜过组件默认的 `px-2`) | -| `tailwindcss` | `^4.3.3` | devDependencies | v4 引擎(只构建期用;运行期产物是编译后的 CSS) | -| `@tailwindcss/postcss` | `^4.3.3` | devDependencies | 构建管线,被 `tsdown.config.ts` 与 `scripts/ui-css.mjs` 共用 | -| `postcss` | `^8.5.26` | devDependencies | 上面的宿主管线 | - -`components.json`(CLI 上下文,非运行期配置):`style: new-york` / `base: radix` / `rsc: false` / `css: src/client/ui/theme.css`,`aliases` 全部指向 `src/client/ui`——**所以 CLI 的默认 `@/lib/utils` 不会出现在这个仓库**(见下文「统一改动」第 2 条)。 - -CLI 曾顺手注入一个 `cn: ^0.3.0` 依赖(npm 上真实存在的同名包,仓库里无任何 import)——已删除并 `pnpm install` 重同步 `pnpm-lock.yaml` / `node_modules`。 - -### Tailwind 接入方式 - -入口是唯一的:`src/client/ui/theme.css`,编译有**两个**消费方但只有一份定义(`tsdown.config.ts` 导出 `compileTailwind()`,`scripts/ui-css.mjs` 复用它产出可视化 harness 的 `tailwind.css`): - -``` -src/client/ui/theme.css ──┬─ tsdown css-inline 插件(生产)→ 内联进 lib/client.js 的