Skip to content

feat: GUI WebUI 像素级对齐 DSH 全链路(渲染路线/校验体系/桥接协议/会话流/权限闭环) - #435

Merged
liuqihonggit merged 49 commits into
mainfrom
w4
Oct 20, 2026
Merged

liuqihonggit merged 49 commits into
mainfrom
w4

Conversation

@liuqihonggit

Copy link
Copy Markdown
Owner

Summary

  • 渲染路线与 spike:ADR 0138 选定 WebView2 + 自研 WebUI 同引擎渲染路线(否决托管 COM 互操作,采纳 CsWinRT 投影 + 免注册 WinRT 清单,NativeAOT 验证通过);WebUI 骨架 + token 生成器 + 帧diff管道,首页像素对齐达 98.6%
  • 像素校验体系:DSG042 三层校验(token/几何/像素)+ DSH 捕获卫星工具与 golden 参考物(CDP 驱动 Edge 捕获、固定主题、负向规则入库);交互态 hover/active/focus golden 对齐 + input-probe 输入命中探针
  • WebUI 桥接协议(ADR 0141):类型化消息面 + 握手 + 冒烟闭环;侧栏真实会话列表(sessions/list + session/select + 渲染 ACK 防假绿);会话流端到端(chat/history 协议 + WebChatFlow 投影 + 引擎接线);差评修复(会话泄漏/流中串话/超时回错/选区保持)
  • GUI 全面对齐 DSH:composer 与消息区几何逐项对齐(29 元素证据链)、输入闭环(停止生成 done.stopped 语义 + 错误条重试 + 输入自动增高)、权限对话框(permission/request→response 协议 + broker 按 Id 分桶 TCS + fail-closed deny)、权限确认全链路 ConfirmAsync 异步化
  • GUI 托管 DSH 前端全量移植 + 宿主 HTTP/WS 协议;侧栏/新建/打开/发送/停止/工具事件/历史向上翻页逐方法接自有引擎;旁白分流 SystemNotice + 忙时排队;工作区闭环选择与注册表持久化
  • 已知缺陷白名单:流式增量透传缺陷另立 TASK043(StreamingFallbackDecorator 全量收集根因),E2E 登记白名单保 CI 可跑

Test plan

  • 单元/组件测试全绿(含会话流端到端 603 绿 + 冒烟 0 失败 + 像素回归零漂移)
  • 真机 CDP 驱动 WebView2 远程调试验证(JIT/AOT 双版输入坐标一致)
  • CI 流水线两段式验证:PR CI 通过后 squash auto-merge 到 main,main 再触发自身 CI 二次验证

盘点三端功能矩阵缺口(交互缝/自定义命令/启动参数/子代理面板/插件UI贡献零消费),规划A-E五阶段:交互缝补齐→入口对齐→UI贡献点→精美度→清理验收
原型已端到端验证: dsh@0.2.0-rc.2本地运行+playwright-core+Edge CDP捕获截图/DOM盒树188元素/双主题421token; 踩坑: msedge CLI screenshot遇WebSocket长连接永久挂起, 改CDP主动截屏; DSG041补像素对齐关联
…免WebSocket挂起, 固定colorScheme主题+首次运行引导弹窗自动关闭, 双层棋盘格page背景解决透明像素/暗色图标误染, golden截图加负向规则入库
…m渲染路线验证, token唯一数据源禁手抄, DOM盒树只作布局规格以golden帧为准
…径(AOT运行时不可用), 采纳官方CsWinRT投影+免注册WinRT清单, PlatformTarget=x64规避x86组件误拷
…T投影定为生产接入路线(托管COM互操作AOT不可用), 四件套配置固化进ADR与TASK053 P6-0
…S行为(composer为div且无hover/active规则)非宿主问题, JIT/AOT双版点击坐标精确一致; hover/focus状态补全归入P1场景矩阵
…eractive-bg-hover/active), placeholder拆分照DSH结构(pointer-events:none+caption色), caret用button-info-fill; 实证DSH按钮无focus样式故仅composer组验证focus, send空输入disabled; 18目标verify PASS(0不一致/0警告)且基帧L3回归等价(meanDelta1.793 t12 1.36%)
决策: pragma+豁免理由,不引入IFileSystem(帧图落盘dumps/根定位/临时目录夹具均为测试基础设施且需真实文件语义,对齐JCC3010/JCC3013既有豁免惯例)

验证: HEAD stash复现36错误确认预存红;修复后测试工程0警告0错误,568测试通过0失败
决策: 开关式增量接入默认保留原MainWindow;TFM平台化+投影开关+x64+清单免注册WinRT;WebView2/CsWinRT版本号上收根props唯一数据源;spike补ExcludeStructura保持独立

验证: GUI/测试/spike三工程编译0警告0错误;真机冒烟 WEBVIEW2-READY runtime=155.0.4283.62 + WEBUI-NAVIGATED success=True 退出码0;webui静态资源随包分发
决策: 类型判别信封type+内联字段([JsonPolymorphic]+BridgeJsonContext源生成,AOT安全);web/ready握手解决页面脚本先于NAVIGATED的时序竞态;未知消息fail-closed+app/error诱导;冒烟退出码新增4=桥接超时/nonce不符

验证: 23单测绿(全类型roundtrip/判别字段/未知type/非法JSON);E2E红(无bridge.js退出码4超时)→绿(退出码0,BRIDGE-SMOKE ok ~100ms);全量GUI 591通过0失败;L3基帧meanDelta1.7927无漂移+交互态0不一致
决策: 协议先proposed再实现后改状态(AGENTS ADR工作流);编号0141避开main文本预占的0140(SSRF)

验证: docs/README计数同步152→153/9→8/125→126;TASK053 P6-0b勾选含红绿证据链
…IJccChatSession不经MainViewModel,开会话先渲染history再灌引擎,手动验证用WebView2远程调试端口CDP驱动
…DSH 实测 y515 微上移 + chip 统一 28px/br8/lh20

row 内距 2px 8px 6px(tools 520 精确); mode-chip 126x28(x517.3 精确); model-chip 180.2x28(x997.5 精确); chevron svg 12->14; 工作区 chip 行高 20 + chip2 宽 106

验证: DOM 转储逐元素与 DSH 表一致; 交互态 20 目标 PASS; L3 meanDelta 1.7799->1.4693; 冒烟退出码 0
…有效值复刻而非照搬DOM结构

记录: L3 1.7799->1.4693; 白名单项(input宽4px透明槽/placeholder覆盖层); 新增 P6-2b 多行自动增高待办
…码块下边距取几何实证16px

- ChatHistoryEntry +Timestamp(宿主 ToLocalWallClock,Web 侧本地 HH:mm);bridge.js 全量消息渲染器(图标/分隔/代码块换行/复制/用时N秒);app.css 消息区整段;msg-column 列 742.4

- tokens.css 生成器升双通道(media 兜底 :not(light) + data-jcc-theme 权威);枚举生成器支持嵌套枚举 + GUI 接入 analyzer(GuiThemeVariant.ToValue)

- 验证: 单测 609/0/3;真机 CDP 47 配对项 Δ(0,0,0,0) 内容高 1160==DSH;样式抽查全 PASS;L3 1.56;冒烟 0
…16px 取舍全记录

验证数据: DOM 47 配对项 Δ(0,0,0,0),内容高 1160==DSH,L3 meanDelta 1.56,冒烟退出码 0
…pped 语义, 每轮 linked CTS 取消在途流 | 决策: 错误条含原因+指引+重试(重发上一条提示词), 停止保留已产出正文
…on) | 决策: F1 真机验收用列文本长度/重发语义判据, 供应商注入走 JCC_* 环境变量通道
…验收标准) | 决策: F1 E2E 该项登记已知缺陷白名单保 CI 可跑, 修复后恢复强制断言
…ompt/level)→permission/response(id,decision),broker 按请求 Id 分桶 TCS,超时/关窗一律 fail-closed deny

非法决策值走 FromValue 反查失败即 deny;同 Id 重复请求只下发一次并直接拒绝;CancelAll 供窗口关闭时全量拒绝

GUI 单测 638 通过 / 0 失败(含 broker 9 例与协议往返),编译 0 警告
…onPendingConfirmationException 抛异常重试机制, 全链路改 ConfirmAsync 异步等待, GUI/TUI/CLI 三方统一实现, 批准副作用对齐 CLI

验证: GUI 644 通过/0 失败/3 跳过, McpToolDispatch 518 通过, CLI+TUI 编译通过
…JccDirectory),C# 侧只实现宿主协议(静态/combo/一元 RPC/流式 WS),自有引擎按 API 逐方法接入

M1 成果: exe --webui 起回环宿主 + WebView2 渲染真实 DSH 界面(65 插件入口全加载, 无 pageerror);修 JsonElement[] 序列化错(Boot API 空数组返回 500);MIT 资产随 LICENSE 再分发

验证: CDP 9222 实机断言 ALL_PASS(ModuleLoader/DSH_BOOT/#root 渲染),截图 dumps/dsh-webui-m1.png;遗留: settings/mutate 未实现导致预览版说明弹窗确认失败
根因: 前端 configForms 用 new Schema(view.schema) 解码命名空间,M1 的 describe 既缺命名空间又缺 schema,写路径打到未实现的 settings/mutate,命名空间停在 loading/写失败

修复: DshSettingsStore 路径式 set/unset + revision + 冲突码;回传与 volatileForm(Config).toJSON() 同构的 schemastery 信封;workspace/initializeDefault 回 null 消除启动错误路径

验证: 单测 7/7;真实 exe E2E 提示页出现-继续-关闭-无报错全覆盖;重载后由宿主读回 welcomeNoticeVersion;新增 JCC_WEBVIEW_DATA_DIR 隔离 E2E 配置目录
按生成的远程契约把具名参数收到 request 下(DshRequestEnvelope),补齐 directoryPicker/pick 与 workspace 全量路由,工作区落 ~/.jcc/dsh-workspaces.json,重启由 workspace/follow 基线恢复

决策: 请求参数形状以 typert 生成契约 wire 名为准(request 信封),不再假设平铺参数;E2E 用 JCC_DIRECTORY_PICK 注入缝跳过原生对话框,单测/手动验收见 TASK053
决策: 会话列表不绑引擎生命周期 — 启动即挂轻量落盘会话实例(State.TranscriptService 读同一份 ~/.jcc/sessions),引擎就绪后热切到引擎实例;根因是前端只在 events 流连接时拉一次全量列表,引擎组装 30s 会导致侧栏永久空白

会话投影: projections{title(custom-title),agentPreset,modelSelection,sessionListMetadata} + asOfSeq=条目数;rename 落引擎 custom-title 并回读;projections 始终输出非 null(严格 codec)

验证: 单测 DshSessionStoreTests 9/9(gui 全量 668 通过) + 手动 exe E2E dsh-webui-sessions.mjs ALL_PASS(隔离 home 预置会话与最小 settings)
决策: 会话实体先于首条消息诞生(ITranscriptService.EnsureSessionAsync 幂等建 meta+空 transcript),模型目录启动读 settings.json、引擎就绪热切 IJccChatSession.VendorModelMap

验证: TranscriptService 22/22、DshSessionStore 18、DshModelCatalogSource 4、GUI 全量 681 通过;E2E dsh-webui-create-session.mjs ALL_PASS(16 项)+ dsh-webui-sessions.mjs 回归 ALL_PASS
决策: 打开快照里 cursor 取前端 emptyCursor(-1)、hasMore=false 让前端不再翻页;assistantStream 基线必给;投影复用 session/projections 的同一次读盘。历史事件映射留 M2-c

验证: DshSessionStore 24 例 + FollowSessionId 3 例;GUI 全量 688 通过/3 跳过;E2E dsh-webui-open-session.mjs ALL_PASS(19) + dsh-webui-create-session.mjs 回归 ALL_PASS
决策: 历史用投影而非改造引擎存储——DSH 的 turn/step/流式块属于界面协议;seq 从 0 单调、消息 id 用 sessionId:seq、消息事件打 surfaceOp=append;工具事件留 M2-c2 由真实流驱动

验证: DshTranscriptProjectorTests 5 例 + 快照 records 断言;GUI 全量 693 通过/3 跳过;E2E dsh-webui-history.mjs ALL_PASS(15),open-session(19)/create-session 回归 ALL_PASS
宿主编排一轮对话:session/prompt 先落 turn/start/step/start/user/message(source.rpcId 回填 requestId)再后台跑引擎,结果落 assistant/message + step/end + turn/end;DshSessionStreamHub 负责订阅广播、seq 接续历史光标、单会话单轮占用。会话列表补 lastPromptAt 投影。

验证: DshTurnRunnerTests 6 例 + DshSessionStore 2 例;GUI 全量 700 通过/3 跳过;E2E dsh-webui-prompt.mjs ALL_PASS(19),history/open-session/create-session 回归 ALL_PASS
TryBeginTurn 同时分配取消令牌,Cancel 取消该轮,RunTurnAsync 全程共用令牌;取消后落 turn/end{kind:'aborted',reason:{kind:'user'}} 并释放单轮占用。取消参数缺失/形状错误走引导式 session/rejected。

验证: DshTurnRunnerTests 8 例 + Dispatcher session/cancel 2 例;GUI 全量 703 通过/3 跳过;E2E dsh-webui-cancel.mjs ALL_PASS(11),dsh-webui-prompt.mjs 回归 ALL_PASS
引擎 ToolCallStart/ToolCallEnd 映射为 DSH tool/call 与 tool/result(callId 配对、surfaceOp=append、isError);实现 session/page 按 beforeSeq+maxMessages 切片,修复历史超 50 条后前端报「宿主尚未实现 session/page」。

验证: 新增 2 例工具事件单测 + 1 例翻页单测;GUI 全量 706 通过/3 跳过;E2E dsh-webui-tool.mjs ALL_PASS(13),prompt/cancel 回归 ALL_PASS
…throughSeq 的尾 N 条并忽略 beforeSeq,满足前端 assertPageThrough 硬断言

新增 DshSessionJournal(~/.jcc/dsh_journal/{id}.jsonl);hub 先落盘再推送、打开流/翻页先按日志重建;旧会话用转录投影播种;messageFeedback/list 返回空成功消除反馈加载失败噪声;补充跨重启/尾条对齐/日志优先单测与刷新重载 E2E
引擎循环干预提示不再混入助手正文; session/prompt mode=queue 串行续跑; E2E 改条件轮询并自动关闭欢迎浮层
补充剩余任务、M2-d 审批桥接范围与五脚本回归基线
@liuqihonggit
liuqihonggit enabled auto-merge (squash) October 20, 2026 16:46
…| 决策: bridge/EngineSession 死分支直接删除对齐 ADR 0142 语义, TUI 处理器补 ConfirmAsync 接口实现(取消 fail-closed 对齐 CLI 先例)
…eb 前端已功能齐备接管默认路径(ADR 0143), 旧 views/view_models/converters/markdown/slash_commands 归档 .xxx/gui_legacy_ui_20261021(-21k行), Dock 子模块退役(gitlink+.gitmodules+42处CI submodule拉取清除), 共享DTO迁移(BackgroundAgentInfo/SettingsVendor*Dto/WorkspaceFile/ShakeAnimationHelper/ViewModelDiagnosticsLogger), Markdig/CommunityToolkit.Mvvm/Inter 依赖解除, 测试 209/209 绿
…ma 校验拒绝导致 0 秒失败, 删除 ci-integration/ci-daily-uncovered/ci-e2e 共 12 处
…+WebView2)物理上仅 Windows 可跑, apps-gui 域切 windows-latest, Host.Tests 留 ubuntu 跨平台覆盖, EnableWindowsTargeting 参数随 runner 切换移除
@liuqihonggit
liuqihonggit merged commit 62a067e into main Oct 20, 2026
@liuqihonggit
liuqihonggit deleted the w4 branch October 20, 2026 18:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant