feat: improve goal mode and Codex App resilience

This commit is contained in:
shiyue
2026-08-18 21:27:58 +08:00
parent 389690af64
commit 8fe31e0a5e
27 changed files with 631 additions and 24 deletions

View File

@@ -71,3 +71,40 @@
- 完成后 `Goal active + 完整目标` 被渲染为居中、接近消息区宽度的大块磨砂面板。
- 长正文包含多行约束与反引号,居中排版和纯文本渲染明显降低可读性。
- 目标视觉应为右侧普通用户气泡;状态反馈应保持短小,不重复正文。
- 用户在真实桌面界面确认 Goal 已显示为普通用户气泡,但缺少明确的“目标模式”身份标签。
- `/goal` 由服务端 Slash/RPC 旁路处理,不会先进入模型回合,因此不能依赖模型主动调用 `ccweb_set_title`
- 当前会话中直接调用 `ccweb_set_title` 成功,证明 MCP 本身可用;缺口位于 `/goal` 旁路没有标题联动,而不是标题 MCP 故障。
- 本轮开始时 `public/app.js``public/style.css``server.js` 没有未提交差异;工作树中的 Codex App 重试改动属于其他任务,必须避开。
- `.planning/.active_plan` 指向另一任务,本轮继续显式维护 `.planning/2026-08-16-goal-bubble-rendering/`,不改全局 active plan。
- 主题架构要求视觉修复只命中用户指出的消息层级Goal 标签应使用专用 selector不能扩大到普通用户气泡或其他卡片。
- CSS 接入需注意共享暗色 `:is()` 的 specificity并在最终验收中核对真实 computed style自动化结构断言不能替代浏览器视觉确认。
- 修改静态 CSS/JS 后需检查 cache bust 与服务实际加载版本;本次不新增主题资产,也不改 welcome 双路径。
- Trellis 当前没有 `.trellis/.current-task`,现有任务列表也没有 Goal 标记/标题修复任务;进入代码阶段前需建立任务资料并提供给实现与检查代理。
- Trellis 要求 Codex 的实现与质量检查由独立子代理执行;当前运行时没有名为 `trellis-implement`/`trellis-check` 的自定义角色,因此后续使用通用 worker并在任务提示中显式要求读取 Trellis PRD、上下文清单和相关规范。
- `home-cc-web` 索引为 `ready`,当前 6444 个节点、14582 条边,可直接用于符号级定位。
- 精确命中 `createMsgElement()``buildMsgElement()``persistCodexAppGoalDisplayMessage()``handleCodexAppGoalSlashCommand()``isTitleLockedByUser()``setCurrentConversationTitle()`
- `setCurrentConversationTitle()` 已具备标题历史、持久化、`session_renamed` 推送和 `broadcastSessionList()`,但它将来源写为 `llm`Goal 自动派生标题需要复用相同广播契约并保留 `derived` 来源语义。
- 手动重命名路径会设置 `titleSource: 'manual'`,已有 `isTitleLockedByUser()` 可作为禁止 Goal 覆盖用户标题的第一道保护。
- `buildMsgElement()` 会把完整消息对象作为 `meta` 传给 `createMsgElement()`;因此在 `createMsgElement()` 读取 `meta.ccwebGoalCommand.action === 'set'`,即可让实时与历史 Goal 消息共用同一标签渲染,无需额外历史迁移。
- `persistCodexAppGoalDisplayMessage()` 当前在消息入栈后统一 `saveSession()`;最小写入方案是在同一保存前尝试派生默认标题,并把 `titleChanged` 返回给 Slash handler 负责发送 `session_renamed` 与列表广播。
- 普通消息自动标题只在标题严格等于 `New Chat`/`Untitled` 时生效,取用户正文前 60 字并把换行替为空格Goal 应沿用同一默认标题判定和长度上限,同时压平连续空白,避免多行 objective 生成杂乱标题。
- `normalizeTitleHistory()` 只接受 `source: 'llm'`;现有普通消息的 `derived` 标题也不写 title history。因此 Goal 自动标题应保持 `titleSource: 'derived'` 并不伪造 LLM 标题历史事件,只推送 `session_renamed` 元数据和会话列表。
- Trellis 相关上下文应覆盖前端组件/质量规范、后端质量规范和跨层契约指南;本次改动同时涉及 DOM/CSS、WebSocket 事件、会话持久化与集成回归。
- 暗金荒野主题的真实 ID 是 `wasteland`,不是 `gilded-wasteland`Goal 标签的主题适配必须限定 `html[data-theme='wasteland']`
- `index.html``app.js` 使用动态 `__CC_WEB_FRONTEND_ASSET_VERSION__`JS 无需手工版本号;`style.css` 仍使用固定 `20260805-usage-loading-inline`,新增标签样式后应推进样式 cache bust并同步既有回归契约中的精确版本断言。
- 现有 Goal 集成回归集中在 `scripts/regression.js` 约 7135 行,已覆盖 display-only 元数据、稳定 request ID、重复请求和刷新持久化适合在同一场景追加标题持久化/广播断言;前端 DOM 标签需要增加静态契约测试。
- Goal thread 的 MCP 注入链路已确认:`ensureCodexAppGoalThread()` 调用 `codexAppThreadParams()`,后者通过 `codexAppThreadConfig()``listRuntimeMcpServerConfigs()` 写入 `mcp_servers.ccweb`;内置配置携带当前 `sourceSessionId`
- 用户怀疑“Goal 未注册 ccweb MCP”的根因不是注册缺失`thread/goal/set` 是 app-server RPC不是模型 turn/MCP 调用。工具可用性不会强制模型调用 `ccweb_set_title`,所以可靠标题仍应由服务端旁路直接派生。
- 第一轮独立计划审查发现:仅广播 `session_list` 只会刷新侧栏,当前聊天顶部标题依赖 `session_renamed`。计划已补成“先向 viewers 发送 `session_renamed`,再广播列表”,回归也必须分别断言。
- 第二轮独立计划复审已通过,无实施阻断项;建议将默认标题判定收敛为 helper并把自动标题严格限定在 `/goal set` 专用路径。
- 现有 Goal 集成场景复用了已经发送过多条普通消息的 `codexAppSession`,其标题早已不是默认值;自动标题正向回归需要另建一个尚为 `New Chat` 的 Codex App 会话,不能在原场景上做错误断言。
- 当前 `wasteland` 用户气泡最大宽度为 `min(42%, 480px)`;标签必须是内容流内的紧凑元素,正文继续依赖现有 `word-break`/`pre-wrap`,不能增加固定宽度或绝对定位造成窄屏溢出。
- 当前目标文件中只有 `scripts/regression.js` 带并发 Codex App 重试差异;实现必须只在 Goal/缓存断言附近追加,保留约 2446 和 main target 注册处的现有重试代码。
- 本机可用 `/usr/bin/firefox`,虽未发现 Playwright/Puppeteer可在服务重启条件满足后用 Firefox headless 做基础桌面/窄屏截图验收。
- 当前 `127.0.0.1:8002` 返回 200 且 `Cache-Control: no-store`;在线 HTML 仍引用 `style.css?v=20260805-usage-loading-inline` 与动态 app.js 版本CSS cache bust 更新后需重新检查实际响应。
- 已完整读取主题验收清单;本次不新增主题/素材,因此资产、主题注册和 welcome 双路径条目不适用,但仍需执行消息 DOM 隔离、`wasteland` computed style、桌面/窄屏、缓存 URL、JS 回归与真实浏览器记录。
- `sendSessionEventToViewers()` 原样转发 payload不自动补 `sessionId`Goal 自动标题事件必须显式携带 `type``sessionId``title``publicTitleMetadata()`
- `normalizeSession()` 已接受 `titleSource: 'derived'``VALID_TITLE_SOURCES` 包含 derived因此 Goal 旁路可安全复用该来源而不修改清洗逻辑。
- `truncateTextValue()` 超长时会追加持久化截断标记不适合标题Goal 标题应使用独立的 60 个 Unicode code point 截取,避免标题中出现换行标记。
- 现有 mock 在 `thread/goal/set` 后会发 Goal 后台 turn包含 `dynamic` 的普通 turn 会执行 `completeMcpToolTurn()`,其结果带 `hasCcwebMcpConfig`,可作为 Goal thread 注册 ccweb MCP 的集成证据。
- 现有 Codex App 回归会话在发送多条普通消息后才进入旧 Goal 场景;新增默认标题测试应在同一服务器内创建独立的 `codexapp-goal-title` 会话,避免旧会话标题已被普通消息派生。

View File

@@ -101,6 +101,48 @@
|-----------|-------|---------|------------|
| 2026-08-16 | 仓库内 `todo-list-csv` 技能短路径不存在 | 1 | 使用技能清单中的实际安装路径 |
## Session: 2026-08-18
### 阶段 7执行真实浏览器桌面与窄屏验收
- **Status:** complete剩余验收已转移至阶段 14
- Actions taken:
- 用户在真实桌面界面确认 Goal 正文已经显示为普通用户气泡。
- 用户指出气泡缺少“目标模式”标记,并确认 Goal 会话标题没有自动更新。
- 将新增缺陷纳入同一任务,最终窄屏和主题验收统一放到阶段 14。
### 阶段 9定位 Goal 标记与自动标题链路
- **Status:** complete
- Actions taken:
- 执行 session catchup 并恢复上一轮 Goal 实施与验证记录。
- 核对当前工作树,识别并隔离另一项 Codex App 重试修复的未提交改动。
- 直接调用当前会话的 `ccweb_set_title` 成功,确认标题 MCP 可用;`/goal` 缺少的是服务端旁路联动。
- 完整读取主题架构与经验教训,确认只为 Goal 用户消息增加专用标签样式,不扩散到普通气泡。
- 完整读取 Trellis 工作流并确认当前没有活跃 Trellis task将在实现前补齐任务资料与独立实现/检查环节。
- 使用 codebase-memory 确认索引就绪,并定位 Goal 渲染、Slash 处理、标题锁定和标题广播函数。
- 读取精确函数源码,确认 Goal 元数据可在统一消息渲染入口生成标签,标题可在 display-only 消息保存周期内派生并实时广播。
- 交叉核对 CSS、缓存版本和现有 Goal 回归位置,确认主题 ID 为 `wasteland`,样式版本需随 CSS 修改推进。
- 确认 Goal thread 已注入 `mcp_servers.ccweb`;标题未变化源于 `thread/goal/set` 不会自动触发工具,而非 MCP 注册缺失。
### 阶段 10审查增量实施计划并修正缺口
- **Status:** complete
- Actions taken:
- 第一轮独立审查指出计划缺少 `session_renamed` 实时事件要求,仅广播列表会让顶部标题保持陈旧。
- 已补充 `session_renamed` + `session_list` 双事件及其回归断言;第二轮完整复审通过。
### 阶段 11实现目标模式气泡标记
- **Status:** in_progress
- Actions taken:
- Trellis 任务 `08-18-goal-mode-title` 已建立、启动并通过上下文校验。
- 实施前重新核对目标文件差异,只有 `scripts/regression.js` 含另一任务改动,已记录不可覆盖区块。
- 检查本地运行服务与浏览器能力:服务在线且 no-store本机有 Firefox 可做后续 headless 验收。
- 完整读取 `create-cc-web-theme` 验收清单,已将与本次消息层级相关的浏览器、缓存、响应式和隔离项纳入收尾门禁。
- 进一步核对标题事件与清洗实现:事件 payload 需显式带 sessionIdderived 来源已被会话规范接受;标题截取不能复用带截断标记的持久化 helper。
- 确认 mock 可验证 Goal thread 的 ccweb MCP 配置,并规划在现有 Codex App 回归中使用独立默认标题会话。
## 5-Question Reboot Check
| Question | Answer |

View File

@@ -6,7 +6,7 @@
## Current Phase
阶段 7执行真实浏览器桌面与窄屏验收
阶段 11实现目标模式气泡标记
## Phases
@@ -57,10 +57,10 @@
### 阶段 7执行真实浏览器桌面与窄屏验收
- [ ] 在桌面视口验证长 Goal 用户气泡
- [ ] 在窄屏验证换行、溢出和系统提示尺寸
- [ ] 确认暗金荒野主题未再生成大块 Goal 系统面板
- **Status:** in_progress
- [x] 用户在桌面真实界面确认长 Goal 已回到普通用户气泡
- [x] 基于真实反馈记录新缺陷:缺少“目标模式”标记、标题未变化
- [x] 将窄屏、主题和最终视觉验收转移至阶段 14
- **Status:** complete
### 阶段 8审查差异并清理临时任务记录
@@ -68,11 +68,50 @@
- [ ] 完成计划记录并删除本任务 TODO CSV
- **Status:** pending
### 阶段 9定位 Goal 标记与自动标题链路
- [x] 使用代码索引确认 Goal 消息渲染、标题派生、保存和广播入口
- [x] 用源码与当前差异交叉验证修改边界,避开其他任务改动
- [x] 确认 Goal thread 已注入 `mcp_servers.ccweb`,但 `thread/goal/set` 不会自动触发工具调用
- **Status:** complete
### 阶段 10审查增量实施计划并修正缺口
- [x] 由独立计划审查员检查标记、自动标题与回归范围
- [x] 修正会导致实现偏差或阻塞的计划问题并完成复审
- **Status:** complete
### 阶段 11实现目标模式气泡标记
- [ ] 复用 `ccwebGoalCommand` 元数据给 Goal 用户消息增加专用类名和标签
- [ ] 增加基础样式及暗金荒野主题适配,不改变普通用户气泡
- **Status:** in_progress
### 阶段 12实现 Goal 新会话自动标题
- [ ] 仅在会话仍为默认标题时从 Goal objective 派生简短标题
- [ ] 持久化派生标题并向当前 viewers 发送 `session_renamed`,再广播会话列表,不覆盖手动标题
- **Status:** pending
### 阶段 13补充标记与标题回归测试
- [ ] 覆盖 Goal 标签 DOM、普通消息隔离、默认标题派生和手动标题保护
- [ ] 同时覆盖标题磁盘持久化、`session_renamed``session_list` 实时更新契约
- **Status:** pending
### 阶段 14运行语法、全量回归与视觉验收
- [ ] 执行语法检查、全量回归和差异格式检查
- [ ] 检查桌面、窄屏及暗金荒野主题下的 Goal 标记视觉
- [ ] 按验收清单记录真实浏览器能力与剩余限制
- **Status:** pending
## Key Questions
1. 设置型 `/goal` 气泡如何持久化而不进入普通模型对话链路?
2. 如何只改变 Goal 命令,不改变其他 Slash 命令的既有行为?
3. 长 Goal 在桌面与窄屏下是否仍保持普通用户气泡布局?
4. `/goal` 绕过模型时,如何可靠更新默认标题且不覆盖用户手动命名?
## Decisions Made
@@ -84,6 +123,10 @@
| Goal 气泡使用独立展示消息路径 | 写入 `session.messages` 并发出 `session_message`,但不调用普通消息运行时,兼顾刷新恢复与防止重复模型执行 |
| `clientMessageId/requestId` 是命令与消息去重键 | 传输重放时可识别同一次设置,避免重复气泡与重复 Goal RPC |
| 校验前失败恢复草稿RPC 已启动后失败保留气泡且不恢复草稿 | 保持即时提交记录,同时避免用户重试产生两条相同气泡 |
| Goal 标签复用 `ccwebGoalCommand` 元数据 | 历史消息与实时消息共用同一渲染入口,无需迁移持久化数据 |
| `/goal` 自动标题由服务端旁路直接派生 | Goal RPC 不经过模型,不能依赖模型主动调用 `ccweb_set_title` MCP |
| 只更新默认标题且保留 `titleSource: derived` | 避免覆盖手动标题,并允许后续模型/MCP继续优化标题 |
| Goal 标题变化同时发送 `session_renamed``session_list` | 前者更新当前聊天顶部标题,后者更新侧栏;缺一都会产生局部陈旧 UI |
## Errors Encountered

View File

@@ -14,3 +14,15 @@
- 已创建主提交 `2efb9d2``feat: improve conversation timeline and agent plans`);阶段 5 完成,准备推送 `main`
- 同步进度后 amend 得到最终主提交 `33c9783`,已成功推送到 `origin/main``4d97446..33c9783`)。
- 六个阶段全部完成,准备删除本次临时 TODO CSV并用收尾提交同步规划状态。
## 2026-08-18
- 用户要求再次执行 CentOS 7 baseline 单文件打包,并提交、推送当前工作树全部修改。
- 按用户要求停止额外视觉/代码审计,仅执行发布技能规定的构建与轻量验证。
- 当前分支为 `main`,远端为 `origin`;工作树中的已跟踪与未跟踪修改均在本次提交范围内。
- PATH 中没有 Bun已找到 `/tmp/ccweb-bun.vyBprA/node_modules/@oven/bun-linux-x64-baseline/bin/bun`,进入重新打包阶段。
- 已用 baseline Bun 1.3.14 完成 `npm run build:single-exe`,重新生成发布目录与 tar.gz进入发布包验证阶段。
- 六项 JavaScript 语法检查通过;发布二进制 MCP `initialize` 返回有效 JSON-RPCtar 清单可读。
- 新发布包 SHA-256`f14c108687b84699d6c4f2301363a36235702db51227da719492a4cdd156d48b`
- 已确认本次提交范围覆盖当前工作区全部已跟踪与未跟踪修改,进入统一暂存与提交阶段。
- 已创建包含全部修改的主提交,进入 `origin/main` 推送阶段。

View File

@@ -13,7 +13,7 @@
| 3. 执行发布包与语法验证 | complete | 技能规定的语法、MCP smoke、tar 清单检查通过 |
| 4. 暂存当前工作区全部修改 | complete | `git add -A` 后无未暂存或未跟踪修改 |
| 5. 创建包含全部修改的提交 | complete | 当前全部修改进入一个新提交 |
| 6. 推送当前分支并确认远端 | complete | 推送成功,当前分支与上游一致 |
| 6. 推送当前分支并确认远端 | in_progress | 推送成功,当前分支与上游一致 |
## 约束
@@ -28,3 +28,9 @@
| 错误 | 尝试 | 处理 |
|---|---|---|
| `bun` 不在 PATH | 1 | 按发布技能查找本机已有 baseline Bun |
## 当前执行
- 日期2026-08-18
- 当前阶段6. 推送当前分支并确认远端
- 用户要求:再次打包;提交并推送当前全部修改;不做额外审计。