feat: add user input history MCP and rebuild release
This commit is contained in:
79
.planning/user-input-history-mcp/findings.md
Normal file
79
.planning/user-input-history-mcp/findings.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Findings & Decisions: 用户输入历史 MCP
|
||||
|
||||
## Requirements
|
||||
|
||||
- 新增一个专用 ccweb MCP,只读返回用户输入内容列表。
|
||||
- 可指定目标对话;未指定时默认当前来源对话。
|
||||
- 默认返回最近 15 次用户输入。
|
||||
- 所有返回输入正文合计最多 1000 个 Unicode 字符,并明确标记截断或仍有更早内容。
|
||||
- 引导表单提交后插入为普通用户消息的内容必须包含在内。
|
||||
- 结果供 LLM 回看用户要求、作为实现验收参考。
|
||||
|
||||
## Research Findings
|
||||
|
||||
- 当前暴露的 `ccweb_list_conversations` 只返回会话元数据,明确不返回对话正文。
|
||||
- 当前 ccweb MCP 工具清单没有读取会话用户输入历史的工具。
|
||||
- 仓库已有其他活跃计划,当前任务使用 `.planning/user-input-history-mcp/` 隔离,避免覆盖根目录或其他任务计划。
|
||||
- Trellis 开发者身份已初始化为 `shiyue`;共享 `.trellis/.current-task` 指向其他任务,因此本任务不覆盖该共享指针。
|
||||
- codebase-memory 项目 `home-cc-web` 索引状态为 `ready`(6308 nodes / 14349 edges),可直接用于函数级定位。
|
||||
- 第二次独立计划审查已通过,契约足以进入代码研究与实施。
|
||||
- MCP 公共工具定义集中在 `lib/ccweb-mcp-server.js` 的 `TOOLS`;现有 `ccweb_list_conversations`、`ccweb_prompt_user` 均在此声明 schema。
|
||||
- 内部 MCP 分派入口是 `server.js` 的 `callInternalMcpTool(tool, args, sourceSessionId, sourceHopCount)`,现有列表工具转到 `listConversationSummaries`。
|
||||
- `listConversationSummaries` 已提供来源会话清洗、limit clamp、会话文件枚举和运行状态等可复用模式;正文读取应另建只读函数,避免扩大摘要接口职责。
|
||||
- 引导表单链路关键函数为 `createCcwebPromptUser`、`handleCcwebPromptUserResponse`、`buildCcwebPromptUserResponseText`;需读取精确源码确认提交内容最终是否由普通 `handleMessage` 持久化为 `role=user`。
|
||||
- 已确认引导表单提交链路:`handleCcwebPromptUserResponse` 用 `buildCcwebPromptUserResponseText` 生成问题/选择/答案正文,再调用普通 `handleMessage(..., { emitUserMessage: true })`;因此提交结果会成为普通 `role=user` 消息,新工具只按角色筛选即可自然纳入。
|
||||
- 待填写的引导卡本身是 `role=assistant` 且携带 `ccwebPrompt`,必须排除;只有用户提交后的普通消息才应返回。
|
||||
- `loadSession(id)` 已是统一、安全的会话 JSON 读取入口,包含 ID 清洗、大小限制、会话规范化和运行时线程索引更新;新查询不应自行读文件。
|
||||
- 公共 MCP `tools/list` 读取 `lib/ccweb-mcp-server.js` 的 `TOOLS`,共享 HTTP/JSON-RPC 调用经 `handleMcpJsonRpcMessage` 与 `isCallableToolName` 进入 `callInternalMcpTool`。
|
||||
- `isCallableToolName` 会自动接受所有 `TOOLS` 中的公开工具;新增工具无需维护额外 allowlist。`CODEX_APP_COMMUNICATION_TOOL_NAMES` 只控制旧 dynamic-tool 兼容集,是否纳入需结合兼容路径调用点判断。
|
||||
- 现有回归函数 `assertCcwebListConversationsScopeContract` 同时断言正式 MCP schema、兼容工具定义和内部分派源码;新工具应补同等级 schema/route 契约,并通过内部 MCP HTTP 做数据行为验证。
|
||||
- `server.js` 的 composer 候选和共享 MCP `tools/list` 都直接展开 `CCWEB_MCP_TOOLS`,因此加入 `TOOLS` 后会自动出现在 `/` MCP mention 与正式 MCP 列表中。
|
||||
- 旧 Codex App dynamic-tool 兼容路径由 `CODEX_APP_COMMUNICATION_TOOL_NAMES` 精确筛选,并最终仍调用同一个 `callInternalMcpTool`。新工具与 `ccweb_list_conversations` 同属只读会话通信能力,应纳入该兼容集合;正式 MCP 仍是主路径。
|
||||
- 测试编写阶段检查工作区时,仅本任务计划/Trellis 文件与测试代理临时清单为新增文件,尚无生产代码改动或与用户既有改动冲突。
|
||||
- 新增聚焦测试 `scripts/ccweb-list-user-inputs-unit.js`,覆盖正式 schema、JSON-RPC/旧内部路由、默认/指定会话、15 条、角色筛选、引导提交、Unicode 总预算、错误码与只读性。
|
||||
- 首次执行按预期失败:公开 `TOOLS` 尚无新工具,调用返回 `unknown_tool`;只读 fixture hash/mtime 断言已独立通过,说明红灯指向缺失实现而非测试环境破坏。
|
||||
- 主审阅发现初版测试有两处需修正:禁止覆盖 `HOME`;提交表单正文会合法包含表单标题,排除未提交卡应按角色/消息 ID 断言。
|
||||
- codebase-memory 一次搜索误报项目未索引,但随后的 `list_projects`/`index_status` 显示 `home-cc-web` 仍为 ready(6387 nodes / 14484 edges),属于瞬时查询异常,无需重建索引。
|
||||
- codebase-memory 收敛重试又返回 `Transport closed`,已按降级规则停用本轮该查询并改用本地 `rg/sed`;定位范围仅限 `sanitizeId`、`truncateTextValue`、`normalizeSession`。
|
||||
- 测试代理已移除 HOME 覆盖、改用消息 ID 排除未提交引导卡,并增加临时目录清理;复跑仍只因 `unknown_tool`/缺失 schema 失败。
|
||||
- 生产实现新增 `listUserInputHistory`,使用 `loadSession` 只读筛选 `role=user`,从最新向前分配 Unicode code point 总预算,再按旧到新返回。
|
||||
- 正式 `TOOLS`、Codex App 旧兼容集合和 `callInternalMcpTool` 已统一注册 `ccweb_list_user_inputs`,没有第二套实现。
|
||||
- 主线程与实现代理在交接边界发生一次 apply_patch 上下文冲突;补丁工具安全拒绝覆盖,最终 diff 仅包含代理的目标改动,无丢失或重复代码。
|
||||
- 语法检查和聚焦测试全部通过,包含 fixture 文件 hash/mtime 不变断言。
|
||||
- 既有 `ccweb-message-reply-unit` 通过,说明新增 fallback 工具未破坏统一发送/旧别名契约。
|
||||
- 完整 `npm run regression` 在约 37 秒内通过;`git diff --check` 无空白或补丁格式问题。
|
||||
- 独立 Trellis 质量审查已通过,无阻断问题;补强了空会话、预算恰好用满(有/无更早输入)和运行时 clamp 测试,复跑通过。
|
||||
- 运行态检查发现除当前对话外,`63b18af6-1b9a-4ad0-8627-f2b5ba22fc39` 仍为 running;按仓库运维规则不得重启 cc-web,因此当前进程尚未加载新 MCP,需待其他对话空闲后重启。
|
||||
|
||||
## Finalized Query Semantics
|
||||
|
||||
- `conversationId`:显式传入则读取该会话;缺省才回退到来源会话。显式无效 ID 不得静默回退。
|
||||
- `limit`:默认 15,允许 1–50;先从全部非空 `role=user` 文本中取最近 N 条。
|
||||
- `maxChars`:默认 1000,允许 1–1000;以 JavaScript Unicode code point(`Array.from`)计数,约束所有返回 `content` 合计。
|
||||
- 预算分配:从最新候选向更早候选分配;遇到剩余预算不足时保留该消息开头并标记 `truncated=true`,更早候选不再返回;最后按旧到新排序。
|
||||
- `hasMore=true`:存在 limit 之外的更早用户输入,或字数预算截断/省略了候选。
|
||||
- 空白/空正文 user 消息不作为“内容”返回;引导表单提交正文是非空普通 user 消息,因此自然包含。
|
||||
- 缺少来源会话返回 `missing_source_conversation`;显式无效 ID 返回 `invalid_conversation_id`;会话不存在返回 `conversation_not_found`。
|
||||
- 返回项包含 `messageId|null`、`createdAt|null`、`content`、`contentChars`、`originalChars`、`truncated`;顶层包含会话 ID、limit/maxChars、总字符数、返回数与 `hasMore`。
|
||||
- Trellis backend 规范目前大多是占位内容;本改动不涉及“部分 JSON 预览”专项规则。实现应沿用现有 `loadSession`、`mcpToolError` 和 `scripts/regression.js` 的实际项目惯例。
|
||||
- 已创建隔离 Trellis 任务 `.trellis/tasks/08-17-user-input-history-mcp/` 并写入完整 PRD;因共享 current task 属于其他工作,本任务不改写 `.trellis/.current-task`。
|
||||
|
||||
## Technical Decisions
|
||||
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
| 工具采用只读查询 | 不应改变会话、消息或运行状态 |
|
||||
| 当前会话默认值由 MCP 服务的来源会话上下文解析 | 与已有跨会话工具的线程级来源语义保持一致 |
|
||||
| 返回最近 N 条后再按旧到新输出 | 查询高效,同时方便 LLM 顺序理解需求演进 |
|
||||
| 1000 字作为整体硬预算,从最新输入向前填充 | 限制最坏上下文体积并优先保留最新验收要求 |
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
| “最多 1000 字”存在逐条或整体预算歧义 | 独立计划审查后选择更保守的整体硬预算,并增加截断/更多标记 |
|
||||
|
||||
## Resources
|
||||
|
||||
- `.trellis/workflow.md`
|
||||
- `AGENTS.md` 中 ccweb MCP 与线程级来源上下文约定
|
||||
84
.planning/user-input-history-mcp/progress.md
Normal file
84
.planning/user-input-history-mcp/progress.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# Progress Log: 用户输入历史 MCP
|
||||
|
||||
## Session: 2026-08-17
|
||||
|
||||
### Phase 1: 代码发现与契约确认
|
||||
|
||||
- **Status:** complete
|
||||
- **Started:** 2026-08-17
|
||||
- Actions taken:
|
||||
- 核对当前暴露的 ccweb MCP 工具清单,确认缺少用户输入历史读取能力。
|
||||
- 读取项目工作流以及计划跟踪技能要求。
|
||||
- 建立隔离的持久计划与已知需求记录。
|
||||
- 完成第一次独立计划审查;根据审查意见补齐整体字数预算、MCP 契约和关键验收用例。
|
||||
- 第二次独立计划审查通过。
|
||||
- 确认 codebase-memory 索引可用;避免覆盖共享 Trellis 当前任务指针。
|
||||
- 定位 MCP schema、内部路由、会话列表和引导表单响应的函数级入口。
|
||||
- 定稿查询参数、Unicode 计数、预算顺序、错误码、返回字段和 `hasMore` 语义。
|
||||
- 读取 Trellis backend 规范;确认无额外目录或错误处理约束,继续遵循现有项目模式。
|
||||
- 创建 Trellis 任务并写入 PRD、implement/check 上下文,未覆盖其他任务的共享 current 指针。
|
||||
- 确认正式 MCP、composer 候选和旧 Codex App 兼容工具的定义复用关系。
|
||||
- 派出 Trellis 测试实现代理;其当前只做代码定位,生产文件保持未修改。
|
||||
- 测试代理新增聚焦失败测试并确认红灯;未修改任何生产文件,已清理其临时 TODO CSV。
|
||||
- 主线程复跑失败测试:1.02 秒退出,7 项因缺少工具/schema 路由失败,只读性断言通过。
|
||||
- Files created/modified:
|
||||
- `.planning/user-input-history-mcp/task_plan.md`
|
||||
- `.planning/user-input-history-mcp/findings.md`
|
||||
- `.planning/user-input-history-mcp/progress.md`
|
||||
|
||||
### Phase 2: 测试与实现
|
||||
|
||||
- **Status:** complete
|
||||
- Actions taken:
|
||||
- 完成失败测试并进入最小生产实现。
|
||||
- 实现 `ccweb_list_user_inputs` 查询、正式 schema、兼容集合和内部统一路由。
|
||||
- 运行两个语法检查与聚焦测试,全部通过。
|
||||
- 运行既有通信单测、完整 regression 与 diff 检查,全部通过。
|
||||
- Files created/modified:
|
||||
- `scripts/ccweb-list-user-inputs-unit.js`(新增测试)
|
||||
- `server.js`(查询逻辑与路由)
|
||||
- `lib/ccweb-mcp-server.js`(正式 schema 与兼容工具集合)
|
||||
|
||||
### Phase 3: 验证与交付
|
||||
|
||||
- **Status:** complete
|
||||
- Actions taken:
|
||||
- 完整 regression、独立质量审查与补强边界测试全部通过。
|
||||
- 检查运行会话;因存在另一个 running 对话,按项目规则暂缓服务重启并记录交付限制。
|
||||
- Files created/modified:
|
||||
- `.planning/user-input-history-mcp/*`(任务审计记录)
|
||||
- `.trellis/tasks/08-17-user-input-history-mcp/*`(PRD 与上下文)
|
||||
|
||||
## Test Results
|
||||
|
||||
| Test | Input | Expected | Actual | Status |
|
||||
|------|-------|----------|--------|--------|
|
||||
| 聚焦测试红灯 | `node scripts/ccweb-list-user-inputs-unit.js` | 因工具未实现而失败 | 7 项 `unknown_tool`/缺失 schema 失败,只读断言通过,1.02s | ✓ |
|
||||
| 生产文件语法 | `node --check server.js`;`node --check lib/ccweb-mcp-server.js` | 通过 | 通过 | ✓ |
|
||||
| 聚焦测试绿灯 | `node scripts/ccweb-list-user-inputs-unit.js` | 8 类断言全部通过 | 全部通过,1.16s | ✓ |
|
||||
| 既有通信单测 | `node scripts/ccweb-message-reply-unit.js` | 通过 | 通过 | ✓ |
|
||||
| 完整回归 | `npm run regression` | 60 秒内通过 | 约 37 秒通过 | ✓ |
|
||||
| Diff 检查 | `git diff --check` | 无错误 | 无错误 | ✓ |
|
||||
| 补强边界测试 | 聚焦脚本:空会话、预算恰好用满、运行时 clamp | 全部通过 | 全部通过,0.82s | ✓ |
|
||||
| 独立质量审查 | Trellis checker 只读审查 | 无阻断问题 | 已通过 | ✓ |
|
||||
| 运行态重启门禁 | `ccweb_list_conversations(status=running)` | 仅当前对话时才重启 | 发现另一个 running 对话,按规则暂缓重启 | ✓ |
|
||||
|
||||
## Error Log
|
||||
|
||||
| Timestamp | Error | Attempt | Resolution |
|
||||
|-----------|-------|---------|------------|
|
||||
| 2026-08-17 | 计划对 1000 字限制的解释可能导致最多约 15000 字输出 | 1 | 改为所有返回正文合计最多 1000 字,并明确预算算法 |
|
||||
| 2026-08-17 | 初版失败测试覆盖 HOME 且误排除提交表单标题 | 1 | 退回测试代理按环境变量规则和消息 ID 修正 |
|
||||
| 2026-08-17 | codebase-memory 搜索瞬时返回 project not indexed | 1 | 用 list_projects/index_status 复核为 ready,避免无谓重建 |
|
||||
| 2026-08-17 | codebase-memory 收敛查询返回 Transport closed | 2 | 停止重复调用,降级为 rg/sed 精确读取目标函数 |
|
||||
| 2026-08-17 | 主线程 apply_patch 与代理最后写入并发导致上下文不匹配 | 1 | 补丁未应用;审阅现有 diff 后确认目标代码完整,再运行验证 |
|
||||
|
||||
## 5-Question Reboot Check
|
||||
|
||||
| Question | Answer |
|
||||
|----------|--------|
|
||||
| Where am I? | Phase 3:验证与交付已完成 |
|
||||
| Where am I going? | 待其他对话空闲后由运维重启加载新 MCP |
|
||||
| What's the goal? | 新增可读取指定/当前对话用户输入历史的只读 MCP |
|
||||
| What have I learned? | 引导表单提交落为普通 user 消息;正式/兼容 MCP 复用同一路由 |
|
||||
| What have I done? | 已实现、测试和审查新 MCP;因运行态门禁暂缓重启 |
|
||||
79
.planning/user-input-history-mcp/task_plan.md
Normal file
79
.planning/user-input-history-mcp/task_plan.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Task Plan: 新增用户输入历史 MCP
|
||||
|
||||
## Goal
|
||||
|
||||
为 cc-web 增加一个只读 MCP,可读取指定对话(默认当前来源对话)最近的用户输入,纳入引导表单提交内容,并把所有返回正文控制在合计 1000 个 Unicode 字符以内,供 LLM 作为验收参考。
|
||||
|
||||
## Current Phase
|
||||
|
||||
Phase 3
|
||||
|
||||
## Phases
|
||||
|
||||
### Phase 1: 代码发现与契约确认
|
||||
|
||||
- [x] 梳理会话消息存储与 ccweb MCP 注册链路
|
||||
- [x] 明确用户输入筛选、默认会话与截断规则
|
||||
- 必须确认普通用户输入与引导表单提交的持久化形态。
|
||||
- 必须确认来源会话缺失、指定会话不存在时的错误语义。
|
||||
- **Status:** complete
|
||||
|
||||
### Phase 2: 测试与实现
|
||||
|
||||
- [x] 编写新 MCP 的失败回归测试
|
||||
- 覆盖默认当前对话、显式指定对话、默认最近 15 条、仅返回 user 内容。
|
||||
- 覆盖引导表单提交消息、合计 1000 字预算、截断标记及缺失来源会话。
|
||||
- [x] 实现指定/当前会话的用户输入读取与限制逻辑
|
||||
- [x] 注册 MCP schema、描述与运行时上下文
|
||||
- **Status:** complete
|
||||
|
||||
### Phase 3: 验证与交付
|
||||
|
||||
- [x] 运行针对性测试并修复发现的问题
|
||||
- [x] 执行相关回归、核验接口并整理交付
|
||||
- **Status:** complete
|
||||
|
||||
## Key Questions
|
||||
|
||||
1. 普通用户输入和引导表单提交在持久层中如何标记、是否都使用 `role=user`?(已确认:提交后经普通 `handleMessage` 持久化为 `role=user`;待提交卡是 `role=assistant`)
|
||||
2. 当前来源对话 ID 从哪个线程级运行时上下文解析?(已确认:JSON-RPC/内部 HTTP 上下文把 `sourceSessionId` 传给 `callInternalMcpTool`)
|
||||
3. MCP 工具注册、参数校验和权限边界由哪些模块负责?(已确认:`lib/ccweb-mcp-server.js` 的 `TOOLS`/`isCallableToolName` 与 `server.js` 的内部 MCP 分派)
|
||||
|
||||
## Decisions Made
|
||||
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
| 默认返回最近 15 条,最终按时间从旧到新排列 | 兼顾最近性与作为验收标准时的可读性 |
|
||||
| 所有返回正文合计默认且硬性最多 1000 个 Unicode 字符 | 避免 15 条输入最坏膨胀到约 15000 字,保证验收上下文可控 |
|
||||
| 从最新输入向前消耗字数预算,最终按旧到新输出 | 优先保留最新验收要求,同时维持自然阅读顺序 |
|
||||
| 预算导致内容或更早消息未完整返回时给出截断/更多标记 | 避免 LLM 将不完整历史误认为完整要求 |
|
||||
| 仅返回用户输入,不混入 assistant/tool/system 内容 | 保持用户原始验收意图纯净 |
|
||||
|
||||
## MCP Contract
|
||||
|
||||
- 工具名为 `ccweb_list_user_inputs`。
|
||||
- 入参:
|
||||
- `conversationId?: string`:缺省时使用 MCP 来源会话 ID。
|
||||
- `limit?: integer`:默认 15,允许 1–50。
|
||||
- `maxChars?: integer`:默认 1000,允许 1–1000;约束所有 `items[].content` 的字符总和。
|
||||
- 返回:
|
||||
- `conversationId`、`requestedLimit`、`maxChars`、`totalChars`、`returnedCount`、`hasMore`。
|
||||
- `items[]` 至少含 `content`、`createdAt`、`truncated`;若持久层有稳定消息 ID,则同时返回 `messageId`。
|
||||
- 排序与预算:先选最近 `limit` 条用户输入,再从最新向前填充 `maxChars` 预算,最终将已选内容按旧到新返回。
|
||||
- 默认当前会话但运行时没有来源会话 ID 时返回明确参数错误;显式指定不存在的会话时返回 not-found 错误。
|
||||
|
||||
## Errors Encountered
|
||||
|
||||
| Error | Attempt | Resolution |
|
||||
|-------|---------|------------|
|
||||
| 计划审查指出 1000 字是逐条还是合计存在歧义 | 1 | 收紧为所有返回正文合计硬上限 1000 字,并固化预算顺序 |
|
||||
| codebase-memory 单次查询误报项目未索引 | 1 | 立即用 list_projects/index_status 复核,项目实际为 ready;后续收敛查询重试,不触发无谓重建 |
|
||||
| codebase-memory 重试返回 Transport closed | 2 | 停止重复 MCP 调用,降级到本地 rg/sed 精确核验小函数 |
|
||||
| 初版失败测试覆盖 HOME 且误排除提交表单标题 | 1 | 已退回测试代理修正环境隔离与角色/ID 断言后再验红灯 |
|
||||
| 主线程生产补丁因代理并发落盘而校验失败 | 1 | apply_patch 安全拒绝覆盖;检查 git diff 后确认代理已完成目标改动,直接进入验证 |
|
||||
|
||||
## Notes
|
||||
|
||||
- 计划与根目录 CSV、`update_plan` 保持一一同步。
|
||||
- 研究发现写入 `findings.md`,测试结果写入 `progress.md`。
|
||||
- 当前运行进程尚未重载:发现另一个非当前对话仍为 running,按项目约定暂缓 `pm2 restart ccweb --update-env`。
|
||||
Reference in New Issue
Block a user