修复完整会话历史与长气泡交互并更新 CentOS 7 发布包

提交当前工作区全部源码、回归脚本、任务记录及重新构建的 Bun baseline 发布包。发布单文件 MCP 初始化及前端资源一致性验证通过。
This commit is contained in:
shiyue
2026-10-10 23:40:16 +08:00
parent 747771a048
commit 69b6db0f5b
71 changed files with 9536 additions and 503 deletions

View File

@@ -0,0 +1,32 @@
# 调研记录
## 用户现象
- Codex App 的 ccweb 表单答案在点击发送时,上一轮实际上已经结束,但 UI 仍按运行中消息走插入。
- 失败卡片显示“插入失败”;点击“重试”仍被当成原 turn 插入,无法把答案作为新一轮发送。
## 代码证据
- `handleCcwebPromptUserResponse` 将答案交给 `handleMessage`;若 `activeCodexAppTurns` 仍有条目,`handleMessage` 无条件转入 `handleCodexAppSteerMessage`。
- `handleCodexAppSteerMessage` 已能处理 app-server 返回 `no active turn to steer` 的部分竞态,但 `waitForSteerReady` 超时会直接失败。
- 前端 `retryCodexAppSteerMessage` 在 `!isGenerating || !currentSessionRunning` 时直接报“当前对话已结束,无法在原 turn 中重试插入”,正好阻断用户要求的新 turn 降级。
- 失败项保留 `clientMessageId`,服务端普通 `handleMessage` 可用该 ID 避免重复持久化;前端需要把临时卡片提升为普通用户消息并启动生成态。
## 设计决策
- 运行中的 turn 继续使用 steer;只有本地运行态已结束或 steer 明确确认旧 turn 不存在时,才转普通 `handleMessage` 新开 turn。
- 新 turn 重试沿用原 `clientMessageId`、正文和附件,避免重复消息;转为普通消息后移除失败操作区并提交消息序号。
- 不把 expectedTurnId 不匹配、网络错误或附件失效等真实失败泛化成新 turn。
## 基线验证
- `node scripts/failed-insert-card-unit.js` 当前通过,但现有断言明确要求 turn 结束后禁止重试,正是需要改掉的旧行为。
- `node scripts/regression.js --target codexapp-stale-running` 当前通过,覆盖了 `no active turn to steer` 的旧 turn 替换;尚未覆盖 `waitForSteerReady` 超时和前端失败卡片转普通新 turn。
- `node --check server.js && node --check public/app.js` 当前通过。
## 实现与回归发现
- 本机 app-server 二进制包含带 expectedTurnId 的无活动 turn 文案,原先只匹配 `no active turn to steer` 的恢复条件不足。
- `turn/completed` 可以先于 steer 错误到达;恢复需要允许本地 entry 已清除,并把旧轮助手消息放回新用户消息之前。
- 已补充普通文字、完成先到、表单答案的端到端回归;截至本阶段均通过。
- 前端仍需等待明确发送成功回执后提交临时消息,并通过稳定消息 ID 合并普通 `session_message`,才能同时避免永久 pending 和重复气泡。

View File

@@ -0,0 +1,14 @@
# 进度记录
## 2026-10-10
- 已确认 codebase-memory 项目 `home-cc-web` 索引可用。
- 已定位前端 `retryCodexAppSteerMessage` 的结束会话拦截,以及后端 `handleCodexAppSteerMessage` 的 ready 超时失败分支。
- 工作区包含其他未提交的会话历史改动,本任务将只修改插入/重试相关代码和回归测试。
- 基线定向回归和语法检查均通过;现有前端单测中的“turn 已结束时不能重试”断言与用户需求相反,下一步先改为新 turn 重试回归。
- 已修复无活动 turn 文案识别、完成先到后的旧输出顺序和自动续发,增加对应 mock、表单答案与竞态回归。
- 最新定向回归:`timeout 60s node scripts/regression.js --target codexapp-stale-running` 通过。
- 正在完善前端重试回执、普通消息合并及失败后的再次重试;此前乐观提交不应作为最终成功依据。
- 已完成 `waitForSteerReady` 的 replaced/timeout 分支、entry 已清理时的直接重分发、完成先到竞态的历史重排,以及前端重试按新 turn 发送与 sent 回执提交。
- 已复核关键差异:`reorderStaleCodexAppTurnMessages` 的 messageIndex 推送、`completeCodexAppSteerMessage` 的索引提交、`updateCodexAppSteerMessage` 返回值调用方,均符合预期。
- 部署状态:重启前检查到除当前对话外仍有 2 个 running 会话(`826deaa0`、`2f1134fe`),按 AGENTS.md 暂缓重启,等其结束后再执行 `pm2 restart ccweb --update-env`。

View File

@@ -0,0 +1,40 @@
# 会话结束后插入转新对话计划
## 目标
当 Codex App 的上一轮已经结束、但页面或服务端仍把本轮视为可插入时,表单答案和普通跟进消息都应自动按新一轮对话处理;失败卡片点击“重试”也应真正发送,不能继续被“仅允许插入原 turn”拦截。
## 阶段
1. [completed] 复现并定位会话结束后的发送与失败重试链路
2. [completed] 补充结束会话后重试自动新开对话的回归用例
3. [completed] 修复前端失败项重试与后端旧轮结束竞态
4. [completed] 运行定向测试、语法检查和完整回归
5. [completed] 复核差异并清理临时跟踪文件
## 验收标准
- 会话结束后点击失败卡片的“重试”会启动普通新 turn,答案只进入一次历史。
- 发送时本地运行态落后于 app-server 时,不再把用户答案永久留在“插入失败”。
- 仍在运行的 turn 继续走 `turn/steer`,expectedTurnId 不匹配等真实错误不被错误降级。
- 普通文本和带附件的表单答案均有回归覆盖,且定向测试、语法检查和完整回归通过。
## 约束
- 保留工作区中其他会话历史改动,不覆盖现有任务目录或 CSV。
- 代码定位优先使用 `codebase-memory-mcp`;FastCtx 只用于读取、编辑和验证本地文件。
- 不重启服务,除非重启前确认除当前会话外没有其他 `running` 会话。
- 新增注释和文档使用简体中文。
## 错误记录
| 错误 | 尝试 | 处理 |
|---|---:|---|
| 表单回归读取到旧轮 done,导致提前检查新输出 | 1 | 等待携带新答案助手消息的 done 后再验收历史 |
## 收尾记录
- 完整回归 `npm run regression` exit 0;定向回归与三个单测脚本、语法检查全部通过。
- 独立后端审查新增 `scripts/codexapp-steer-recovery-unit.js`(5 项通过),覆盖 ready 等待期间旧轮结束、completion 先到、保存失败与错误分类。
- 部署:重启前检查到除当前对话外仍有 running 会话(`826deaa0`、`2f1134fe`),按约束暂缓重启;待其结束后执行 `pm2 restart ccweb --update-env` 生效。
- 临时跟踪文件:本任务 CSV 已按 todo-list-csv 流程清理。

View File

@@ -0,0 +1,112 @@
{
"evidenceDir": "/tmp/cc-web-mermaid-export-dirEq0",
"cases": [
{
"name": "flowchart",
"expected": {
"viewBox": "-8 -8 289 56.600006103515625",
"width": "100%",
"height": null,
"foreignObjects": 5,
"labelBoxes": [
{
"x": 0,
"y": 0,
"width": 0,
"height": 0,
"text": ""
},
{
"x": 0,
"y": 0,
"width": 0,
"height": 0,
"text": ""
},
{
"x": 0,
"y": 0,
"width": 32,
"height": 25.600006103515625,
"text": "开始"
},
{
"x": 0,
"y": 0,
"width": 64,
"height": 25.600006103515625,
"text": "处理订单"
},
{
"x": 0,
"y": 0,
"width": 32,
"height": 25.600006103515625,
"text": "完成"
}
]
},
"size": {
"width": 578,
"height": 114
},
"filename": "mermaid-1.png",
"mime": "image/png"
},
{
"name": "sequence",
"expected": {
"viewBox": "-50 -10 450 287",
"width": "100%",
"height": null,
"foreignObjects": 0,
"labelBoxes": []
},
"size": {
"width": 900,
"height": 574
},
"filename": "mermaid-2.png",
"mime": "image/png"
},
{
"name": "html-label",
"expected": {
"viewBox": "-8 -8 95 172.8000030517578",
"width": "100%",
"height": null,
"foreignObjects": 3,
"labelBoxes": [
{
"x": 0,
"y": 0,
"width": 0,
"height": 0,
"text": ""
},
{
"x": 0,
"y": 0,
"width": 64,
"height": 51.19999694824219,
"text": "中文标签第二行"
},
{
"x": 0,
"y": 0,
"width": 32,
"height": 25.600006103515625,
"text": "结束"
}
]
},
"size": {
"width": 190,
"height": 346
},
"filename": "mermaid-3.png",
"mime": "image/png"
}
],
"browser": "156.0"
}

View File

@@ -0,0 +1,15 @@
# 定位记录
- 用户要求 Mermaid 下载图片,默认 2 倍;使用 PNG 无损格式。
- 项目使用 Node.js,前端主入口 public/app.js;Mermaid 相关文件还有 public/index.html、public/style.css。
- codebase-memory-mcp 的 home-cc-web 索引状态为 ready。
- 工作区已有多项其他任务改动,包括 public/app.js,需要局部修改。
- 已定位 serializeMermaidSvg、getMermaidSvgText、svgTextToPngBlob 和 ccDownloadMermaidDiagram;已有复制 PNG 的转换能力,应复用。
- codebase-memory 的 get_code_snippet/trace_path 连接关闭(Transport closed),后续使用已命中的文件范围进行本地阅读。
- 本机有 Firefox 和 geckodriver,可使用隔离浏览器页面验证真实导出。
- 导出改为 svgTextToPngBlob(svgText, 2),输出 .png;复制默认保持 1 倍。
- 独立代码审查补充使用 UTF-8 Data URL 作为 SVG 图片来源,避开部分浏览器对 Blob + foreignObject 的 Canvas 安全限制;下载按钮 title 和 aria-label 明确 PNG、2 倍。
- 第一轮成功验证(Firefox 156.0,使用倍率实现与 Blob 来源):流程图 578×114、时序图 900×574、中文换行图 190×346,MIME、PNG 文件头和 2 倍尺寸均通过,实际下载文件存在;目视检查中文与换行完整。
- 因独立审查随后修改了图片来源,正在用最终 Data URL 实现重复必要的真实浏览器验证。
- 最终 Data URL 实现复验通过,三类图表尺寸与上述结果一致;PNG 中中文与 HTML 换行可见。浏览器报告已保存为本目录 browser-report.json;原始图片保留于 /tmp/cc-web-mermaid-export-dirEq0/。
- 页面入口通过 computeFrontendAssetVersion 按文件内容计算资源版本,修改前端后刷新页面即可加载最新代码,无需重启服务。

View File

@@ -0,0 +1,13 @@
# 进度
- 2026-10-10:读取仓库规范、前端质量规范和规划技能;检查工作区与索引状态。
- 已建立与 update_plan 同步的三阶段 CSV,后续先定位导出函数。
- 定位完成:下载目前直接保存 SVG;svgTextToPngBlob 已用于复制图片,可以扩展倍率后复用。
- 独立计划审查通过。进入实现阶段,父代理准备真实 Firefox 导出验证。
- 已编写 /tmp/cc-web-mermaid-export-browser.cjs:使用项目真实 Mermaid 函数与 10.9.1 资源,在隔离 Firefox 页面点击按钮并校验导出文件头、宽高、中文和切换行为。
- 实现完成:转换函数 scale 默认 1,下载显式 2;下载文件扩展名 .png;保留错误处理与按钮恢复。node --check public/app.js 通过。
- 独立代码审查完成:转换改用 Data URL,按钮无障碍标签与提示明确格式和倍率。语法与 diff 空白检查通过。
- 浏览器三类图表首轮全部通过,抽查 PNG 中中文与箭头完整;最终 Data URL 版本正在复验,证据保存于临时隔离目录。
- 最终 Data URL 版本复验通过:3 类图表下载的 PNG MIME、文件头、固有尺寸 ×2、按钮恢复和源码切换均符合预期;真实下载文件存在,中文换行目视抽查通过。
- 保存精简浏览器报告 browser-report.json;复核静态资源按内容计算版本,刷新即可生效,未重启服务。
- 全部步骤完成,清理本任务 CSV,保留规划与验证记录。

View File

@@ -0,0 +1,34 @@
# Mermaid 图片下载
目标:气泡中的 Mermaid 下载 PNG 图片,默认导出尺寸为图表固有尺寸的 2 倍。
## 阶段
1. [completed] 定位 Mermaid 下载入口并确认导出约束。
2. [completed] 将下载改为默认 2 倍 PNG 图片。
3. [completed] 验证图片格式、尺寸及页面行为。
## 约束
- 沿用现有下载按钮与渲染流程。
- 保留中文标签、图表样式和完整边界,导出比例不受页面缩放或设备像素比影响。
- 工作区已有其他任务改动,public/app.js 只修改 Mermaid 导出相关区域。
- 不重启服务,除非确有必要且没有其他运行中的会话。
- 完成后清理本任务临时 CSV。
## 错误记录
- Codebase Memory 读取源码和调用链时 Transport closed;已完成符号定位,降级为已知范围的本地源码阅读,不重复调用失败工具。
- Mermaid CDN 测试资源直连 25 秒、代理 30 秒未下载完;已切换可续传的后台下载,浏览器验证将使用本地同版本资源。
- CDN 不支持 Range,取消续传,改为延长总下载上限的异步下载。
- 首个实现代理出现 upstream encrypted continuation context 验证失败,未完成修改;已重新派发完整且简明的实现上下文。
- 首轮浏览器验证总计 60 秒超时(Firefox 启动较慢);增加浏览器验证总时限并增加阶段输出,仅对浏览器测试调整时限。
- 第二轮 Firefox 成功启动但加载页面超出 25 秒;确认主机负载 31,限制隔离浏览器内容进程数并增加页面加载时限。
## 完成记录
- 最终实现真实 Firefox 156.0 测试通过:流程图、时序图和中文 HTML 换行标签均成功下载 PNG;尺寸分别为 578×114、900×574、190×346,均为固有宽高的 2 倍。
- PNG 文件头、MIME、文件名和按钮恢复通过;图形/代码切换正常;抽查导出图片中文、换行与箭头可见且完整。
- node --check public/app.js、git diff --check -- public/app.js 通过。
- trellis-update-spec 复核:此次只调整已有前端导出辅助函数和下载入口,没有新增跨层协议;具体导出约定保存在任务 PRD、findings 与 browser-report.json,无需扩充通用规范。
- 无依赖变更、无服务重启、无提交。