更新对话标题和 MCP 描述并重新打包 CentOS 7 发布包

This commit is contained in:
shiyue
2026-10-19 23:45:43 +08:00
parent 7bef7d7ddc
commit e56b3a57bb
10 changed files with 100 additions and 11 deletions

View File

@@ -0,0 +1,2 @@
{"file":".trellis/spec/frontend/state-management.md","reason":"检查当前会话、后台更新与切换隔离"}
{"file":".trellis/spec/frontend/quality-guidelines.md","reason":"检查语法和行为验证"}

View File

@@ -0,0 +1,9 @@
# 调查记录
- 项目为原生 JavaScript 前端,入口 public/index.html 默认 title 为 CC-Web。
- 初步索引搜索未发现 document.title 动态更新逻辑。
- codebase-memory 索引状态 ready。
- public/app.js 中 resetChatView、applySessionSnapshot、handleServerMessage 的 title_updated 分支以及聊天标题编辑完成逻辑直接写入 chatTitle.textContent,应统一维护标签页标题。
- 实际事件名为 session_renamed;session_list 当前不主动刷新聊天标题,需要同步当前会话名称且避开编辑中的草稿。
- 服务端每次计算 app.js 内容哈希并用于入口页版本,可刷新页面加载本次改动,无需重启服务。
- 主代理读取源码片段时 codebase-memory 出现 Transport closed,已按已定位符号用本地读取降级;实现子代理仍可访问索引。

View File

@@ -0,0 +1,2 @@
{"file":".trellis/spec/frontend/state-management.md","reason":"沿用当前会话状态更新链路"}
{"file":".trellis/spec/frontend/quality-guidelines.md","reason":"遵守原生前端与静态资源版本约定"}

View File

@@ -0,0 +1,5 @@
# 当前对话同步浏览器标题
浏览器标签页的 title 随当前打开的对话名称更新;切换对话、自动生成标题和手动重命名后保持同步。没有当前对话时使用 CC-Web。复用现有当前对话标题入口,不改变页面视觉样式。
验收:检查初始加载、切换、重命名、后台会话更新与无当前会话的标题表现;完成语法检查与必要行为验证。

View File

@@ -0,0 +1,23 @@
# 进度记录
- 已确认需求是浏览器标签页标题随当前对话名称同步。
- 已读取项目约定并建立任务记录、计划和 CSV;验证探索交由只读子代理并行进行。
- todo-list-csv 技能未安装;按项目约定直接维护 CSV。
- 已定位 public/app.js 的会话快照、列表刷新、重命名和重置路径;实现子代理仅修改 app.js,主代理负责文档与验证。
- 只读验证发现现有回归没有 document.title 行为断言;采用临时浏览器验证,不新增长期测试文件。
- app.js 已通过 setChatTitle 统一维护页头与浏览器标题,覆盖载入、重命名、列表刷新与重置;编辑中不由列表刷新覆盖草稿。
- node --check public/app.js 通过。
- Chromium 149.0.7827.55 通过 11 项真实 DOM 行为检查:初始、打开、切换、当前重命名、后台隔离、列表同步、编辑草稿、提交、取消、无名称回退与重置默认;无页面脚本异常。
- 浏览器使用本地夹具、模拟通信和临时暴露入口,未访问真实会话或调用生产 API;临时脚本在 /tmp,未加入项目。
- 独立审查通过:currentSessionId 变化均覆盖标题更新,后台会话隔离正确,Escape 恢复后通过 blur 同步;git diff --check 通过。
- 已评估规范更新:本次沿用既有会话状态更新模式,无需新增规范条目。
- 工作完成,无需重启服务;用户刷新页面即可加载更新。
## 后续交付
- 按用户修正,标签页仅显示当前对话名称,已去掉 CC-Web 后缀。
- 已按用户原文更新设置标题、发送消息、列出对话、更新计划、创建持久对话和多问题表单六项 MCP 工具描述。
- 已重启 ccweb,并在当前模型工具列表确认六项新描述生效。
- 用户要求重新打包并提交推送全部修改,不再进行额外审计。
- 使用本地 Bun 1.4.0 按 bun-linux-x64-baseline 目标重新生成发布包;必要语法检查、可执行文件 MCP initialize、压缩包完整性及前端源码一致性验证均通过。
- 发布包 42.96 MiB,SHA-256:2ee61a827b56f2ff538ced64c344ff73470e3df042db61d2f9360d67eebef49f。

View File

@@ -0,0 +1,26 @@
{
"id": "conversation-document-title",
"name": "conversation-document-title",
"title": "当前对话同步浏览器标题",
"description": "",
"status": "completed",
"dev_type": null,
"scope": null,
"package": null,
"priority": "P2",
"creator": "shiyue",
"assignee": "shiyue",
"createdAt": "2026-10-19",
"completedAt": "2026-10-19",
"branch": null,
"base_branch": "main",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [],
"notes": "",
"meta": {}
}

View File

@@ -0,0 +1,13 @@
# 任务计划
1. [completed] 定位当前对话名称与浏览器标题的更新入口。
2. [completed] 实现浏览器标题随当前对话同步。
3. [completed] 验证切换、重命名和默认标题并收尾。
## 约束
只修改相关前端逻辑,不重启正在承载其他运行会话的服务。
## 工具异常
- codebase-memory 的 get_code_snippet 在主代理端连接关闭,已使用本地文件读取;子代理端索引正常。

View File

@@ -16,7 +16,7 @@ const CCWEB_REPLY_MODES = Object.freeze({
ONE_WAY: 'one_way',
RETURN_AND_CONTINUE: 'return_and_continue',
});
const CCWEB_SEND_MESSAGE_DESCRIPTION = '向指定 ccweb 对话发送一条消息,并以“来自某对话”的气泡在目标对话中展示。必须填写 replyMode:仅当来源不需要目标结果时使用 one_way;涉及分析、实现、测试、验收、完成后汇报或来源后续依赖目标结果时必须使用 return_and_continue。两种模式的工具调用都会立即返回,不阻塞也不等待目标对话完成;return_and_continue 只表示目标完成后由系统异步回传并触发来源继续运行,不表示当前调用需要等待。调用后不要使用 sleep、不要轮询等待,也不要反复查询 pending reply;继续当前工作或结束本轮即可。';
const CCWEB_SEND_MESSAGE_DESCRIPTION = '向指定对话发送一条消息,并以“来自某对话”的气泡在目标对话中展示。必须填写 replyMode:仅当来源不需要目标结果时使用 one_way;涉及分析、实现、测试、验收、完成后汇报或来源后续依赖目标结果时必须使用 return_and_continue。两种模式的工具调用都会立即返回,不阻塞也不等待目标对话完成;return_and_continue 只表示目标完成后由系统异步回传并触发来源继续运行,不表示当前调用需要等待。调用后不要使用 sleep、不要轮询等待,也不要反复查询 pending reply;继续当前工作或结束本轮即可。';
const CODEX_APP_COMMUNICATION_TOOL_NAMES = new Set([
'ccweb_list_conversations',
'ccweb_list_user_inputs',
@@ -55,7 +55,7 @@ const TOOLS = [
},
{
name: 'ccweb_list_conversations',
description: '列出当前 ccweb 中可投递消息的对话。默认返回全部对话;scope=children 时只返回当前来源对话通过 ccweb_create_conversation 直接创建的持久子对话。只返回 ID、标题、Agent、运行状态和更新时间,不返回对话正文。',
description: '列出当前对话列表中可投递消息的对话。默认返回全部对话;scope=children 时只返回当前来源对话通过 ccweb_create_conversation 直接创建的持久子对话。只返回 ID、标题、Agent、运行状态和更新时间,不返回对话正文。',
inputSchema: {
type: 'object',
properties: {
@@ -112,7 +112,7 @@ const TOOLS = [
},
{
name: 'ccweb_set_title',
description: '设置当前 ccweb 对话标题。只作用于当前来源对话;用户手动重命名后会成功返回但忽略,不再覆盖用户标题。',
description: '设置当前对话标题,新对话明确需求后调用一次;普通进展、子步骤、实现细节都不要改名,只有主要目标发生明显变化才再次调用。',
inputSchema: {
type: 'object',
properties: {
@@ -128,7 +128,7 @@ const TOOLS = [
},
{
name: 'ccweb_update_plan',
description: '当原生 update_plan 工具不可用时,在当前 ccweb 对话展示并更新多步骤计划。每次传入完整计划;开始、完成步骤时重新调用以同步状态。简单任务无需调用。',
description: '当原生 update_plan 工具不可用时,优先调用此工具展示并更新多步骤计划。每次传入完整计划;开始、完成步骤时重新调用以同步状态。简单任务无需调用。',
inputSchema: {
type: 'object',
properties: {
@@ -155,7 +155,7 @@ const TOOLS = [
},
{
name: 'ccweb_create_conversation',
description: '创建一个新的 ccweb 持久对话。Agent 固定继承来源对话,不作为参数指定;只用于需要在会话列表中长期追踪、后续可继续对话的工作流;一次性并行研究应优先使用子代能力。工具调用会立即返回。启用 requestReply 后,默认由系统异步回传结果;除非用户明确要求轮询,否则不主动轮询等待。',
description: '创建一个新的持久对话。只用于需要在会话列表中长期追踪、后续可继续对话的工作流;一次性并行研究应优先使用子代能力。工具调用会立即返回。启用 requestReply 后,默认由系统异步回传结果;任何尝试轮询等待持久对话返回的行为都是禁止的',
inputSchema: {
type: 'object',
properties: {
@@ -241,7 +241,7 @@ const TOOLS = [
},
{
name: 'ccweb_prompt_user',
description: '在当前来源 ccweb 对话前台渲染一个多问题表单。工具会立即返回,不等待用户;用户提交后,ccweb 会把问题、选择和答案作为一条普通用户消息发回当前对话。',
description: '调用此工具实时渲染一个多问题表单,工具会立即返回一个待定状态;用户提交后,会把问题、选择和答案作为一普通用户消息发回当前对话。',
inputSchema: {
type: 'object',
properties: {

View File

@@ -7142,6 +7142,11 @@
chatAgentBtn.setAttribute('aria-expanded', willOpen ? 'true' : 'false');
}
function setChatTitle(title) {
chatTitle.textContent = title || '新会话';
document.title = currentSessionId ? chatTitle.textContent : 'CC-Web';
}
function resetChatView(agent) {
abortToolDetailRequests();
clearPendingMissingSessionConfirmation();
@@ -7177,7 +7182,7 @@
collabAgentIdsByToolUseId = new Map();
closedCollabAgentIdsByToolUseId = new Map();
updateGenerationControls();
chatTitle.textContent = '新会话';
setChatTitle('新会话');
updateSessionIdBadge();
updateCwdBadge();
updateReloadMcpButtonUI();
@@ -7235,7 +7240,7 @@
(snapshot.messages || []).length,
);
setLastSessionForAgent(snapshot.agent, currentSessionId);
chatTitle.textContent = snapshot.title || '新会话';
setChatTitle(snapshot.title);
updateSessionIdBadge();
setCurrentAgent(snapshotAgent);
migratePendingNotesToSession(snapshot.sessionId, snapshotAgent);
@@ -8554,7 +8559,11 @@
reconcileSessionCacheWithSessions();
renderSessionList();
if (currentSessionId) {
setCurrentSessionRunningState(!!getSessionMeta(currentSessionId)?.isRunning);
const currentSession = getSessionMeta(currentSessionId);
setCurrentSessionRunningState(!!currentSession?.isRunning);
if (currentSession && chatTitle.contentEditable !== 'true') {
setChatTitle(currentSession.title);
}
}
if (pendingInitialSessionLoad) {
pendingInitialSessionLoad = false;
@@ -8884,7 +8893,7 @@
}
});
if (msg.sessionId === currentSessionId) {
chatTitle.textContent = msg.title;
setChatTitle(msg.title);
if (msg.titleEvent) {
currentOutlineTitleHistory = normalizeOutlineTitleHistory([...currentOutlineTitleHistory, msg.titleEvent]);
updateUserOutlinePanel();
@@ -12763,7 +12772,7 @@
chatTitle.style.overflow = '';
chatTitle.style.textOverflow = '';
const newTitle = chatTitle.textContent.trim() || originalText;
chatTitle.textContent = newTitle;
setChatTitle(newTitle);
if (save && newTitle !== originalText && currentSessionId) {
send({ type: 'rename_session', sessionId: currentSessionId, title: newTitle });
}