# dsh-terminal-panel 独立测试报告(最终验收 vFinal) | 项 | 值 | |---|---| | 报告版本 | **vFinal**(最终验收;自动 e2e + Lead 3101 真实 agent manual 结果已全部并入) | | 测试执行 | qa-verifier(独立 QA) | | 日期 | 2026-10-19 Asia/Shanghai | | 契约 | `docs/architecture.md`(含 2026-10-19 更新:`live_` 前缀 / 自动打开 / 截图=文本屏幕 / `visibleText` viewport 语义 / task-4 后 run→独立命令会话 + screenshot 默认目标) | | 被测版本 | `packages/dsh-terminal-panel`(host `lib/index.js` + `lib/host/**`;client `client-src/**` → `lib/client.js` 构建产物),含 task-4(host run/screenshot 重做、sessions 注入、进程终止)、task-5(client 传 sessionId) | | 测试环境 | DSH 0.2.1-rc.2,dev profile,QA 专用 dev host **127.0.0.1:3105** | | 自动化入口 | `tools/qa-e2e.mjs`(Playwright 系统 Chrome + 真实 fetch/SSE 断言) | | **最终验收 run** | `qa/artifacts/2026-10-19T10-52-17-172Z/`(`summary.json` / `console.log` / 13 张截图) | | 测试计划 | `qa/test-plan.md` | --- ## 0. 结论(TL;DR) - **最终验收(最新 host+client,全新 3105 host,串行 `--slow`):PASS 44 / FAIL 0 / SKIP 1 / MANUAL 29**(run `2026-10-19T10-52-17-172Z`,73.5s)。 - **验收门槛(architecture.md §6.3)全部满足**:host 启动无插件报错、`/sessions` 200、client bundle 无 console error、面板可开/输入/resize/关闭、SSE 实时、UTF-8/ANSI/长输出、未鉴权 401、错误 JSON;**拦截 pwsh(B)**、**自动打开面板**、**`live_terminal_screenshot` 文本截图(C)** 均由 Lead 在 3101 用真实 deepseek-flash agent 复测 **PASS**。 - **P2-1 cwd 已闭环**:client 新建终端携带 `sessionId`,host 解析会话工作区;QA e2e U-06 实测 `cwd=C:\Users\LANCANG\Desktop\Code\lancang`(会话工作区)、`sessionId` 已写入 SessionInfo;Lead 3101 实测 `cwd=…\BIG DATA`(会话工作区)PASS。裸 HTTP `/create` 不带 sessionId 仍回退 host 启动目录,属预期。 - **P1-2 run+screenshot 已修复并验证**:task-4 重做后,`live_terminal_run` 返回首行 `[terminal ]`、无 wrapper 噪声;`live_terminal_screenshot` 缺省选中最新 command 会话并返回干净可见屏文本 + `[terminal … 86x50 cursor (0,24) exited]`,agent 原样贴出(Lead 证据 `tools/artifacts/tool-test-final.png`)。 - host 单测 **116/116 PASS**;client 构建 **393,231 B(384.0 KiB,gzip 100.3 KiB)**;e2e 期间插件 HTTP 调用 0 次 4xx/5xx、无 plugin console error/pageerror。 - 剩余:**E-11 desktop profile 安装**由 Lead 安装后用 58966 探测确认(QA 不重启用户 Desktop);另有 P3 观察 4 项(DSH 内部偶发 pageerror、e2e 环境并发 flake、剪贴板首行比对、关闭会话后 shell 进程残留),均非验收阻断。 - 未触碰用户 Desktop DSH(58966 PID 25976 全程不变)与 `D:\DSH`;未重启 3101/3103/3104;QA 侧未发送任何对话消息、未消耗模型额度。 --- ## 1. 环境与版本 | 项 | 值 | |---|---| | 最终 dev host | `& "D:\DSH\resources\runtime\cli\bin\dsh.cmd" --profile dev --no-open --port 3105`;PID 6436;日志 `qa/artifacts/devhost-3105-final2.log` | | host 日志 | 仅 `dsh web:` + llm model listing,无插件错误行 | | 端口 | 3105 = QA host;3101 = Lead 集成 host(QA 未动);3103/3104 未动;58966 = 用户 Desktop(PID 25976,全程不变) | | 浏览器 | 系统 Chrome(`C:/Program Files/Google/Chrome/Application/chrome.exe`),Playwright headless | | client 构建 | `node tools/build-client.mjs` @ 2026-10-19 18:46:26;单文件 393,231 B;externals 与契约 §5.3 一致;xterm + CSS 打包进 bundle | | host 单测 | `node --test --test-concurrency=1 packages/dsh-terminal-panel/tests/*.test.mjs` → **116 pass / 0 fail**(含 registry/shell/tools/intercept/wrapper/session/screen/ring/ansi) | | 契约更新 | architecture.md 已同步 `visibleText` viewport 语义、`live_terminal_run` 独立命令会话 + render `[terminal ]`、`live_terminal_screenshot` 缺省目标(最近可见会话,command 优先) | --- ## 2. 执行记录与总体统计 | 阶段 / run | 说明 | 结果 | |---|---|---| | 阶段 A 干跑(3104 skeleton) | 验证 e2e 机制(选择器/cookie/401/JSON/SSE 断言) | 6 PASS / 27 FAIL(host 路由未实现,预期) | | 预验收 run1 `10-07-26-684Z` | 首次全量;U-11/H-07 为脚本问题、H-16 为产品问题 | 40 PASS / **3 FAIL** / 1 SKIP | | 预验收 run2 `10-10-44-820Z` | 修 e2e SSE 解析与 guide 选择器 | 42 PASS / **1 FAIL**(H-16) | | 预验收 run3 `10-13-05-088Z` | 增加 E-04;host 修复前 | 43 PASS / **1 FAIL**(H-16) | | 正式验收 run `10-15-44-399Z` | 上一轮最新代码 + 重启 host | **44 PASS / 0 FAIL / 1 SKIP** | | Lead 3101 e2e `10-36-36` | Lead 用 QA e2e 在集成 host 串行跑 | 44 PASS / 0 FAIL / 3 SKIP(未带 `--slow`/`--host-log`) | | 最终轮尝试 A `10-41-57-134Z` | 最新代码、全新 host;H-06/H-08 环境 flake | 42 PASS / **2 FAIL**(H-06/H-08) | | 最终轮尝试 B `10-44-57-684Z` | 同上,复现 flake | 42 PASS / **2 FAIL**(H-06/H-08) | | 隔离验证 `10-47-29-909Z` | `--http-only`(无 UI 阶段) | 29 PASS / 0 FAIL / 7 SKIP → H-06/H-08 通过 | | 诊断 run `10-49-59-176Z` | 清理 2 个 orphaned pwsh/OpenConsole 后 `--keep-sessions` | **44 PASS / 0 FAIL / 1 SKIP** | | **最终验收 canonical `10-52-17-172Z`** | 再次全新 host、串行 `--slow --host-log`、正常清理 | **44 PASS / 0 FAIL / 1 SKIP / 29 MANUAL(73.5s)** | > **环境 flake 说明**:最终轮 A/B 的 H-06/H-08 失败(交互会话 30s 内无 shell 提示符/无输出)与同一代码的 `--http-only` 全过、清理 orphaned `pwsh.exe`+`OpenConsole.exe` 后全量过相互印证,判定为 **PTY/进程环境竞争 flake**,不是产品回归;已作为环境噪声归档。Lead 也观察到 B-05 在与其 agent 测试并发时 flake 一次、单独跑稳定 PASS,同类归档。 --- ## 3. 验收门槛(architecture.md §6.3) | 门槛 | 结果 | 证据 | |---|---|---| | dev host 启动无插件报错 | **PASS** | `qa/artifacts/devhost-3105-final2.log`;`/ping` 200、`/sessions` 200 | | `/dsh-terminal-panel/sessions` 带 cookie 200 | **PASS** | H-01 | | client bundle 加载无 console error | **PASS** | E-03:marker=true、clientLog=true、pluginConsoleErrors=0、pageErrors=0;`01-app-loaded.png` | | 面板可开、可输入、可 resize、可关 | **PASS** | U-04/U-05/U-07/U-09/U-10;`04/05/07/09/13-*.png` | | SSE 实时输出 | **PASS** | H-08:首帧 snapshot、output 帧延迟 **8ms**、`seq` 单调(13→17)、data `{id,seq,chunk}` | | 拦截生效(真实 agent,B) | **PASS**(Lead 3101) | E-09/T-02:chat “运行命令 · Output intercept-ok”,右侧栏出现 command 会话(title=命令、cwd=会话工作区)、屏幕 intercept-ok、状态“已退出(0)”,agent 回复正确;证据 `tools/artifacts/agent-test-02/03.png` | | agent 命令会话自动打开面板(§5.2) | **PASS**(Lead 3101,同一证据) | E-12/T-11:面板未开时自动打开右侧栏“终端面板”并选中命令 tab | | `live_terminal_screenshot` 返回屏幕文本(C) | **PASS**(Lead 3101) | E-10/T-04:run 首行 `[terminal ]`、无 wrapper 噪声;screenshot 缺省选中最新 command 会话,返回 `[terminal Get-Location; … 86x50 cursor (0,24) exited]` + 干净可见屏文本;agent 原样贴出;证据 `tools/artifacts/tool-test-final.png` | | 新建终端在会话工作区(P2-1) | **PASS** | QA U-06:`sessionId=session-d63c2d80-…`、`cwd=C:\Users\LANCANG\Desktop\Code\lancang`;Lead 3101:`cwd=…\BIG DATA` | | desktop profile 安装后同样工作 | **待 Lead**(Lead 即将安装并用 58966 探测;QA 不重启用户 Desktop) | E-11 | --- ## 4. 分项结果(最终验收 run `10-52-17-172Z`) ### 4.1 UI e2e(A:可见终端面板) | ID | 结果 | 说明 / 证据 | |---|---|---| | U-01 打开 dev GUI | PASS | 标题 DeepSeek Harness,`__DSH_TERMINAL_PANEL__=true`;`01-app-loaded.png` | | U-02 关闭预览弹窗 | PASS | 无遮挡;`02-after-overlays.png` | | U-03 打开会话(不发送消息) | PASS | composer 已可见(复用已有会话);`03-conversation.png` | | U-04 Ctrl+Shift+B → guide「终端面板」 | PASS | 右侧栏展开,guide 入口 1 个;`04-right-sidebar-guide.png` | | U-05 点 guide → 面板 body | PASS | `[data-dsh-terminal-panel="body"]`;工具栏按钮齐全;`05-panel-open.png` | | U-14 空态/新建入口 | PASS | `[data-dsh-tp-action=create]`,phase=ready | | U-06 新建终端 → xterm | PASS | 新会话 running 86x44、**cwd=会话工作区、sessionId 已传**;`06-xterm-created.png` | | U-07 输入命令 → 屏幕输出 | PASS | `Write-Output 'qa-hello-…'`,1ms 内屏幕出现 | | U-08 中文输出 | PASS | `中文-qa` 正确渲染,无 `�`;`08-xterm-chinese.png` | | U-09 resize | PASS | 86x44 → 68x31,观察到 2 次 POST `/resize`;`09-resized.png` | | U-10 UI 关闭会话 | PASS | 关闭按钮 → host `/sessions` 移除;`13-session-closed.png` | | U-11 刷新后重开面板/重连 | PASS | host 会话保留、snapshot 保留旧输出、UI 恢复屏幕文本;`10-after-reload.png` | | U-12 多会话 + 标签切换 | PASS | 两会话、切换标签各自屏幕正确、host snapshot 不串台;`11-multi-session.png` | | U-13 面板截图/复制按钮 | PASS | 剪贴板 161 字符、内容为当前屏幕文本;`12-screenshot-button.png`;首行比对差异为观察项 O-3 | ### 4.2 HTTP/SSE 契约(architecture.md §4.4) | ID | 结果 | 说明 | |---|---|---| | H-01 `/sessions` 200 + SessionInfo[] | PASS | 字段/枚举校验通过 | | H-02 无 cookie → 401 | PASS | admit 失败行为符合契约 | | H-03 `POST /create` | PASS | 200 `{session}`;SessionInfo 合法(裸 HTTP 无 sessionId → cwd 回退 host 启动目录,预期) | | H-04 `/create` 缺省尺寸 | PASS | 默认 120x30 | | H-05 `GET /snapshot` | PASS | `{info,screen,text,cursor}` 形状正确 | | H-06 `/input` → snapshot 输出 | PASS | shellReady=true,输出延迟 213ms | | H-07 SSE 帧格式/首帧 | PASS | `text/event-stream`;首事件 snapshot;data JSON;retry 控制帧不误判 | | H-08 SSE 实时性/seq | PASS | 延迟 8ms(<2s);output 帧 `{id,seq,chunk}` seq 单调 | | H-09 全局 `/events` sessions 事件 | PASS | 新建会话后收到 `sessions` 事件 | | H-10 `/resize` 生效 | PASS | 200 `{ok:true}`,snapshot.info 同步 90x25 | | H-11 `/close` | PASS | 200;列表移除;snapshot 404 `{error}` | | H-12/H-13/H-15 错误处理 | PASS | 缺 id/未知 id → 4xx `{error}`;非法 JSON → 400 且服务不崩 | | H-14 resize 参数校验 | PASS | 非整数→400;越界值→安全钳制(记录策略,非缺陷 O-2) | | H-16 >1MB 请求体 | PASS | **413 JSON**,服务不崩溃 | | H-17 SSE 反复连接 | PASS | 5 次连接/断开后正常 | | H-18 20s 心跳 | PASS(--slow) | 21s 内收到 heartbeat | | H-19 测试会话清理 | PASS | 关闭本次创建的全部会话(4 个),无 API 残留 | ### 4.3 边界与数据正确性 | ID | 结果 | 说明 | |---|---|---| | B-01 中文/UTF-8 | PASS | snapshot.text 精确包含中文串 | | B-02 UTF-8 跨块(大段 CJK) | PASS | 2283 字节可见屏,无 `\uFFFD` | | B-03 ANSI | PASS | screen 保留 `\x1b[` SGR;text 无 ESC | | B-04 长输出 500 行 | PASS | 可见屏 44 行(=rows),尾部含 `qa-line-500` | | B-05 `exit` | PASS | state=exited、exitCode=0(并发重负载时曾 flake 一次,单独跑稳定) | | B-06 多会话隔离 | PASS | 两会话输出互不串台 | | B-07 ~64KB 输入 | PASS | 200;Ctrl-C 恢复,会话 running | | B-08 Ctrl-C | PASS | 中断前台命令,会话保持 running | | B-09 非法 UTF-8 字节 | SKIP | JSON 协议无法承载,超出契约范围 | ### 4.4 客户端加载与环境 | ID | 结果 | 说明 | |---|---|---| | E-01 host 启动日志无插件报错 | PASS | 无 error/exception;插件 `ctx.logger` 未落 stdout,故以无错误行 + HTTP 200 判定(证据强度一般) | | E-03 client bundle 加载 | PASS | marker + clientLog;plugin console error/pageerror=0;plugin HTTP 失败=0 | | E-04 刷新/多会话后运行时异常 | PASS | plugin 相关异常=0;非 plugin 的 DSH 页面异常单独记录(O-1) | ### 4.5 host 单元测试(QA 独立运行) - 命令:`node --test --test-concurrency=1 --test-reporter=spec packages/dsh-terminal-panel/tests/*.test.mjs` - **116 pass / 0 fail**(约 2.6s)。 - 覆盖:ansi/ring/screen/session/wrapper/intercept/intercept-value/tools/registry/shell;含 `live_terminal_run` 独立命令会话、render 首行 `[terminal ]`、screenshot 缺省目标、send/read 默认交互终端、超时/abort 映射、`resolveSessionCwd`(live/持久化/前缀容错)等 task-4 新语义。 - QA 在开发期独立跑单测曾发现并回报 2 个真实缺陷(`ByteTail` 多 chunk 字节上限失效、文本无限增长)与 2 个测试自身问题,host-engine 已修复,当前全绿。 ### 4.6 契约一致性静态审查(S-01..S-11) | ID | 结果 | 要点 | |---|---|---| | S-01 路由方法/路径/请求/响应 | PASS | 全部 `prefix:/dsh-terminal-panel`,形状与 §4.4 一致;额外 `/ping` 不冲突 | | S-02 SSE 格式/心跳/清理 | PASS | `event:/data:`、`retry: 1000` 控制帧、20s `: ping` 心跳、close 幂等清理 | | S-03 SessionInfo | PASS | 字段/枚举与 §4.4 一致(H-01/H-03 + 单测双重校验) | | S-04 工具 | PASS(task-4 后更新) | 7 个 `live_terminal_*`;JSON Schema 参数/严格 output.schema;`run` render 首行 `[terminal ]`;`screenshot` 缺省目标=最近可见会话(command 优先);send/read 默认交互终端 | | S-05 拦截与回退 | PASS | 仅 `pwsh`/`bash`;后台/沙箱参数与失败 → `next()`;value 与内置 pwsh foreground 一致(单测) | | S-06 配置项/默认值 | PASS | §4.1 全部配置项一致并钳制 | | S-07 host 运行时契约 | PASS | 无 `@deepseek-ai/*` import;`inject=['tools']`;headless xterm `createRequire` | | S-08 client 注册 | PASS | locale/sidebarRightTabs/guide/slots、自动打开(每标签页一次)、传 sessionId;factory 返回 `{apply,inject}` | | S-09 构建产物 | PASS | 单文件 ModuleLoader 包装、externals 仅平台基座、xterm+CSS 打包、`