R26 集成批 3:MCP 连接监督 + 插件治理阶段 2 + MCP 工具 golden + 桌面端文案修复批 - #27
Merged
Merged
Conversation
管理员断言 trust_level(read_only | external_effect,默认最保守的一档)落 0074 迁移, 与插件工具自述取 AND 决定最终 sideEffect:只有「断言 read_only」且「工具自述只读」 才落到 none 档(顺着 canUseToolForTaskPlanRole 的既有规则对 research/review 可见), 其余一律 external_effect。自述来自 ctx.tools.register() 收到的 readOnlyHint === true—— dsh defineTool 在 0.1.0-rc.8 按白名单归一化,本身没有任何只读声明面。 同批把 plugins.status 加上 crashed(每插件熔断的落库态),装配用的部分索引一并排除它。 线协议版本推进到 2:描述符增必填 selfReportedReadOnly。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
「正在拉…/没拉到/拉不到」是开发口里的 fetch/pull,占满了桌面端每个视图的加载与 错误态(68 处、19 个文件)。新增 load-state-copy.ts 作为唯一句式来源:各模块词典 只给「加载的是什么」这个主语,句子由 loadingZh/En、loadFailedZh/En(自带重试按钮 的错误块)、loadFailedRetryZh/En(无重试入口)拼。 顺带落地术语统一:子运行→子任务的加载态、提议详情→变更申请详情、军团面板→小队面板、 运行→执行记录,英文侧 Couldn't load(无宾语)补回宾语。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
离线施工不引入 @modelcontextprotocol/sdk,按 MCP 的 stdio 线协议自建最小客户端, 形状照 packages/plugin-host/src/protocol.ts 与 plugin-host-client.ts 那套子进程 RPC: - jsonrpc.ts:换行分隔的 JSON-RPC 2.0 增量解析。单行上限 1MB(成型行按 UTF-8 字节精确判、 未成帧的残留按码元数保守预判,避免 O(n²)),超限即协议错误并让解码器进终止态; 非 JSON / 非 jsonrpc:"2.0" 的噪声行丢弃并计数。 - session.ts:spawn、initialize(版本协商,只接受已知清单内的版本)、notifications/initialized、 tools/list(跟 cursor 翻页,重复 cursor 与超 20 页均判协议错误,整代拒绝不留半套)、 tools/call(超时后发 notifications/cancelled);服务器反向请求一律回 -32601; notifications/tools/list_changed 只标脏不中途换清单;stderr 尾部 8KB; 优雅关闭走「关 stdin → SIGTERM → SIGKILL」三档。 - spawn.ts:默认子进程启动口(不过 shell、env 全量替换、不 detached)。 - 经 package exports 的 ./stdio 子路径导出,主入口 index.ts 保持零 IO。 顺带接上 M1b 留的合并点:content.ts 的 sanitizeModelFacingText / neutralizeMcpFenceTags / 围栏标签表改成转调 @workhub/tools 的共享实现,本包不再持有算法副本(签名与行为逐字不变, content.test.ts 一行断言未改)。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- plugin-host-client:清单条目从裸路径升成「路径 + 信任断言」,toolSpecs 按插件逐个查 断言再算分级;熔断改成先归因(在飞调用属于哪个插件 / 只装了一个时就是它),归因得到 就只关那一个插件并可选落库 status='crashed',归因不到才落回整插件面熔断;reload 一并解除。 - callTool 的 catch 把插件抛出的错误消息经 sanitizeModelFacingText 中和后再进 ToolResult (R26 M1b Note 点名的相邻缺口),口径与正常返回值一致。 - plugins 服务/路由/openapi/api-client:安装可指定信任级别,PATCH /api/plugins/:id 改一次, 落 plugin.trust_changed 审计;审计 detail 的 capability 与这次调用真正生效的分级同源。 - golden 扩成两档:管理员断言 read_only 时自述只读的工具落 none 并对 research/review 可见, 没有自述的那个原地不动。夹具补一个不自述只读的第二个工具来钉住这条不对称。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
聚焦盒:看改动卡去掉 diff、回放卡改说「可回退」而不是快照、知识卡去掉「沉淀」; 「苹果聚焦盒」「预览环境」「原生窗口」这些开发期说法换成用户能懂的话;权限开关 「派 run / 动网盘 / Touch drive」改「派活给 AI / 改网盘文件」;范围 ID 换成「组织 / 工作区 / 角色 / 会话的标识」;LLM_API_KEY 与 .env 路径退回部署文档;dsh 缩写去掉。 小队面板:全端统一叫「小队 / Squad」(此前导航叫军团、命令面板叫小队);定时任务与 主动提醒的内部名(SLA sweep / 阶梯 / 补投 / proactivity)改成用户视角,两张对照表连 同新增的 stage 表一起搬进 army/locales.ts,未登记的取值落「其它…」而不是渲染裸 id。 枚举兜底:labels.ts 与 search.ts 查不到映射时不再把原始枚举值印给用户,改回退到 「未知状态 / 未标注 / 还原点 / 其它」;labels.test.ts 新增一条按 contracts 枚举取值域 逐个断言「有映射」的测试——以后漏配文案在测试里红,不在界面上露。 失败提示(12 处):error.message 不再顶替产品文案,改用 withErrorDetail 把产品句子 放前面、原始报错作括号里的次级信息并截断。 术语统一:工作项/工单 → 任务;提议/变更提案 → 变更申请;快照 → 还原点。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- 网页只读清单多一行信任级别,并给 status='crashed' 一句自己的说法(不再被读成「还好好跑着」)。 - 桌面设置页每行多一行断言 + 一个按钮:放宽成只读断言要两段式确认(那一步是在撤掉一道人工门), 收紧回最高风险立即生效。分区顶部一句话说清「只读断言只对自述只读的工具生效」。 - 新增文案全部进两端各自的 locales.ts;服务层的熔断原因改成运维诊断(落 load_report 与日志), 界面对 crashed 渲的是词典里那句话。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
apps/api/src/services/mcp-client.ts,形状照 plugin-host-client.ts,三处刻意不同: 熔断粒度是「一台服务器」而不是整个 MCP 面(一台 GitHub 服务器起不来不该带走文件系统服务器); 一台连不上不让整次装配失败;长连接因此需要空闲回收。 - 懒连接 + 连接缓存;活子进程上限 8,超了关最久未用(LRU);空闲 10 分钟回收(回收不是失败, DB 状态不动、工具清单留着,下次用到重新握手)。 - 重连预算:同一台 10 分钟内失败 3 次,第 4 次熔断并停止重试,reload() 解除。 **连接失败与非预期退出计进同一份预算**——只数退出的话,命令根本不存在的服务器永远不熔断。 - 崩溃/超时/连不上时在飞调用返回**工具错误结果**而不是抛异常;错误文本同样过围栏中和与 32KB 上限。 - 每次调用落 mcp.tool.called(形状对齐 plugin.tool.called,capability = 描述符的 minScope), 审计写失败 fail-open 但留结构化日志。 - 真实连接结果经 updateConnectionResult 写回 mcp_servers(M0 的 setEnabled(true) 之后必须跟一次)。 - DB 来源显式接线:useMcpServerSource() 供 M4 在 server.ts 调;不接线一台都不连、一次 PG 都不查。 - 29 条测试(假子进程):env 白名单/引用越界 fail-closed/结果中和与截断/审计形状与写失败/ 崩溃隔离与预算耗尽/reload 解除/空闲回收/LRU/整代拒绝/list_changed 刷新/超时不计预算。 四条回归对照均已验证变红后还原(预算上限、崩溃改抛异常、关掉空闲回收、env 改透传父环境)。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
项目设置:agent-run / 主区观察者 / 项目治理 / AI 治理 / deadline 前瞻天数 / 工单停滞 天数阈值,改成用户读得懂的说法(「这个项目里 Cuu 的所有对话和任务执行」「多少天没 进展算停滞」…),校验提示同步。 日程:「物化 / Materialize」是数据库词,主按钮、状态标签、结果提示与 toast 一律改 「写入时间线 / Added to the timeline」。 其余:顶栏「打开聚焦盒」→「打开快捷入口」(聚焦盒是内部设计代号);「这个客户端不 支持工作台数据」→ 告诉用户去更新;右栏文件区去掉「变动 = 提议 manifest 的变更集」这 种解释界面自己的定义句;群聊模式弹层「按能力细分:建任务 / 派 run / 动网盘」改成按 事项说;编辑器去掉括号里的「快照已不可读」;启动失败面板改说「发给技术支持」并补上 英文(此前只有中文标题配英文堆栈);邀请 token 全端统一叫「邀请码」。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ensureConnected 同时是「调一个工具之前」的必经之路。list_changed 之后的那次刷新如果失败 (服务器回 JSON-RPC error),原实现会把异常抛到调用路径上,等于拿次要路径的故障去伤主路径。 改成留着上一份清单继续用并记一条 mcp_tools_refresh_failed 日志;加一条对应测试 (回归对照已验证:把 catch 拿掉即变红)。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
分析屏三条状态:「正在读取项目网盘上下文」「正在调用澄清模型生成反问」「界面只显示 工具调用和当前状态」——上下文/澄清模型是内部叫法,最后一句在解说界面自己(它想说的 其实是隐私保证),改成「正在读项目网盘里的文件」「正在想该问你什么」「你的需求原文 不会显示在这里」。 变更申请下一步不再描述点开后界面长什么样(英文里还夹着 diff);「缺少启动 AI 执行的 客户端能力」改成让用户去更新;「轻卡窗口」(屏幕阅读器播报)改成「卡片」;回滚快照 改说「改动前的版本」;英文侧的 execution trace / Curation budget / Eval budget 换成 用户语言;军团计划预算 → 小队计划预算。 偏好面板:模型包 → 形象(aria)、实验锁定 → 暂未开放、「可恢复交互 / 软隐藏 / 锚点 / 桌面桥接」全部换成用户看得懂的描述,英文里那句 must not move 的规格原话一并去掉。 QA 场景与桌宠示例脚本:file-only、smoke、daemon、should show 这些内部词清掉。 cuuStart.defaultIntent 全仓零引用且是一句指令口吻的文本,删掉而不是改写。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- qa:plugin-smoke 去掉恒返回 null 的假守卫,装配真的 createHumanReservedGuard(四个仓储换成 Proxy 包的内存实现,守卫多调一个方法会当场炸而不是安静跑绿)。同一次冒烟跑两条路: 断言只读 + 自述只读的 echo 调用成功、零升级、零还原点;同插件里没有自述的 write_note 仍开一条 user_forbidden 升级并以 409 中断执行。 - qa:r1-pg-plugin-smoke 补 0074 的列/CHECK 断言、PATCH 信任级别的 403/422/落库、 改一次断言后工具当场分成两档、以及 plugin.trust_changed 的前后两档审计。 - README 插件小节补「信任级别」两段(含 readOnlyHint 的写法)与每插件熔断的说法。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
变更提案 → 变更申请(Cuu 词典与工作台页面都叫这个,通知点开后不该换一个词); 「AI 运行失败」→「这次执行失败了」;「更省的执行路径」→「换个更省的做法」; 托盘「隐藏主窗」补全成「隐藏主窗口」。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
侦察到基线之后 r26/integration-5 已经独立落了同一条修复(callTool catch 里的 sanitizeModelFacingText)。把常量名、注释与调用位置对齐到那一版,并采纳它更好的一点: 审计留原始错误信息(给人排障用),只有进模型可见通道的那一份才中和。 合并时这一处取任一侧即可。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
# Conflicts: # apps/api/src/services/plugin-host-client.ts
缺口一(写法漏网):AgentRun|agent_run 的正则不匹配 `agent-run` / `agent run`, 项目设置里那句「所有 Cuu 对话与 agent-run」因此一直通过。 缺口二(纯英文整片漏检):判据是「含汉字的字面量」,于是 Run trace / Loading trace… / Curation budget / Eval budget 从来没被扫过。新增 collectCopyLiterals(收全部字面量、 剔除 key/类型/import 这些标识符位置)+ BANNED_EN,只在词典文件(i18n*/locale*/ locales/**/*-copy.ts)上跑——那里除了 key 之外都是文案,普通产品文件里的接口路径与 选择器不受影响。 缺口三(纪律第 5 条一个词都没进表):补 15 组中文规则——解释型文案、对界面自身的解说、 路线图语言、开发运行方式、内部设计代号、内部结构名、内部实体名混排、数据库词、 「正在拉/没拉到」、接口字段名直出、后台子系统名、能力协商词、功能开关内部状态、 设计理由泄漏。 术语统一(工单/工作项 → 任务)**不**进禁词表:这两个词在 apps/api 的 LLM 提示词里是 合法的内部术语,做成正则 90% 是误报;口径记在 glossary-dejargon.md 里靠审查守。 新增 check-copy-terms.test.ts:每条新规则一个会红的用例 + 词典/非词典的分工边界 + term-allow 豁免 + key/类型/import 不参与英文扫描。check-copy-terms.ts 的 main() 加了直接执行判据,测试 import 不再触发全库扫描。 顺带修掉本批范围内被新规则逮到的存量:workbench/settings/render.ts 的「派 run / 动网盘」 (与聚焦盒那份重复的第二处)、风险巡检 → 风险汇总、缺少必要参数 → 说清楚去哪儿处理、 editor 英文侧的 diff、Cuu 主动性 → Cuu 主动做的事。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
M6 的 MCP 工具 golden 需要引用 packages/mcp-client 的纯翻译函数 (describeMcpTools/toMcpToolSpecs/renderMcpContent),apps/api 此前没有任何文件引用过这个包 (M2/M3/M4 尚未在本集成分支落地)。补依赖声明并重新生成 pnpm-lock.yaml(纯 workspace 内部 链接,不拉任何新第三方包)。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
MCP 服务器自报的工具经 packages/mcp-client(M1)翻成 ToolSpec 后经 toModelTools 对模型可见, 此前没有 golden 覆盖这条第三方文本进模型上下文的通道。照 plugin-tool.golden.test.ts 的先例, 用 echo-server-tools.ts 的常量夹具(零 IO、不起任何服务器进程)钉住五层: - mcp-tool-spec:echo/write_note 翻成 ToolSpec 之后的非函数面,read_only/external_effect 两档管理员断言各一份——读写分级真值表在模型可见面上的体现。 - mcp-tool-model-view:toModelTools 里的那两项 + 三种任务计划角色的可见性。新事实:同一台 MCP 服务器内,echo(none)对 research/review 可见,write_note(external_effect)不可见—— 分级按工具生效,不是按服务器生效(插件工具阶段 0 全是 external_effect,没有这个区分)。 - mcp-tool-engine-request:两套引擎请求体里的 MCP 那两项,复核 KNOWN_ENGINE_DELTA 在 none/external_effect 两个值上都成立。 - mcp-tool-edge-cases:拒绝规则的结果 + 有损命名挂指纹后的公开名。 - mcp-tool-content:renderMcpContent 对围栏注入尝试 + 非文本块 + 较长文本的模型可见文本。 description/content 的截断态改用精确断言而不是落整份 expected(同 PLUGIN_TEXT_MAX_CHARS 的 处置),避免仓库背几十 KB 与内容无关的重复字符、且保持 firstDiff 可读。另新增一条断言:装了 MCP 工具后系统提示词逐字节不变(成立,与插件同口径)。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
五层覆盖范围、角色可见性矩阵按工具而非按服务器区分这条新事实、KNOWN_ENGINE_DELTA 在 none/external_effect 两档复核结果、截断态精确断言的取舍、以及给下一个碰 packages/mcp-client 的工位留的已知负债(content.ts/to-tool-spec.ts 仍是局部复制的 sanitizeModelFacingText,未消费 M1b 落的共享版本)。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
glossary-dejargon.md:WorkItem/AgentRun/Snapshot/Proposal 四行补上「唯一叫法」, §9 速查表补 Agent Army→小队、Spotlight→快捷入口、materialize→写入时间线, §10.2 checklist 从 6 条加到 10 条(界面不解说自己 / 加载态统一句式 / 枚举人话兜底 / 两个门禁指路)。 收尾把审查清单外但同源的术语漂移一并清掉:看板与时间线的「工作项」、日程草案摘要、 风险汇总卡的「工单停滞」、时间线依赖校验的三条错误文案、editor 与 proposal 的 「可用快照回滚」、timeline 的 PM mode。命令面板的 keywords 数组刻意保留旧叫法 (那是搜索词不是展示文案),加注释写明。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
R26 集成批 3:MCP 连接与监督(M2)+ dsh 插件治理阶段 2(逐工具风险分级 / 每插件熔断 / 真守卫冒烟)+ MCP 工具 golden(M6)+ 桌面端文案修复批(F1)。
一、MCP 连接与监督(r26/m2-mcp-connection,5 commits)
packages/mcp-client/src/stdio/(经./stdio子路径导出,主入口仍零 IO):换行分隔的 JSON-RPC 2.0 最小客户端,不引官方 SDK(工人全程离线安装;替换点唯一在session.ts)。协议面:initialize版本协商(客户端报2025-06-18,接受2025-03-26/2024-11-05,其余 fail-closed);握手 10s 超时并收干净子进程;未声明capabilities.tools就如实零工具;tools/list跟 cursor 翻页到底(上限 20 页,同一 cursor 回第二次判协议错误);服务器反向请求(sampling / roots / elicitation)一律回-32601;list_changed只标脏下次刷新;调用超时发notifications/cancelled,迟到回复丢弃;单行 1MB 上限,stderr 尾部 8KB 留证。apps/api/src/services/mcp-client.ts:按工作区读mcp_servers启用行懒连接;熔断粒度是一台服务器(重连 10 分钟 3 次,连接失败与非预期退出计同一份预算,reload()解除);活子进程上限 8(LRU);空闲 10 分钟回收(不算失败,live: false单独字段);每调用审计mcp.tool.called(形状对齐plugin.tool.called,capability= minScope);真实连接结果写回仓储。env 走 M1 白名单 +WORKHUB_MCP_SECRET_*引用式密钥。content.ts改为转调@workhub/tools的sanitizeModelFacingText,行为逐字不变。二、插件治理阶段 2(r26/x-plugin-phase2-risk-grading,5 commits)
0074给plugins加trust_level(默认external_effect)。最终sideEffect= 管理员断言 AND 工具自述:只有管理员断言read_only且宿主register()面上readOnlyHint === true才映成none(minScope: plugin:<id>:read),其余一律external_effect。dshdefineTool@0.1.0-rc.8没有任何只读/破坏性声明位(isConcurrencySafe刻意不当只读信号)。低风险档选none不选sandbox_file(只读工具不该开永远用不上的还原点)。agent-runner.ts一行未改:none档不进人工保留门、对 research/review 可见,都是既有规则的自然结果。source_path的quarantine,归因不猜(崩时只有一个插件的调用在飞、或宿主只装了一个插件才归因;否则退回整面熔断);plugins.status增crashed,落库走pluginCrashSink(不接线不碰 PG);热重载一并解除两种熔断。qa:plugin-smoke去掉假守卫,接真实humanReservedGuard:只读档调用直接跑通(升级事件 0、不开还原点),外部影响档仍停下转人(user_forbidden升级带risk_category: external)。真 PG 门补信任级别读写断言(一次性容器实跑:0072 + 0074 落地,plugin.trust_changed轨迹)。payment/publish一类词的插件工具即使只读档也照样转人(与 MCP 设计里「服务器名参与分词」同性质),界面尚未解释;现存 dsh 插件没写readOnlyHint的仍在最高档,这是默认拒绝该有的样子。三、MCP 工具 golden(r26/m6-mcp-golden,3 commits)
5 份新 expected:
mcp-tool-spec(两档管理员断言下 echo/write_note 的 ToolSpec 非函数面)、mcp-tool-model-view(toModelTools两项 + 五种角色可见性——分级按工具生效而非按服务器)、mcp-tool-engine-request(两套引擎请求体里 MCP 两项,KNOWN_ENGINE_DELTA在none/external_effect两值上都成立)、mcp-tool-edge-cases(2 条拒绝 + 4 条成功含两个有损命名挂指纹)、mcp-tool-content(围栏注入尝试与非文本块的模型可见文本)。装了 MCP 工具后系统提示词逐字节不变。「能红」演练改一个字母 3 份同时红。四、桌面端文案修复批(r26/f1-desktop-copy-fix,7 commits)
load-state-copy.ts;「派 run / 物化到时间线 / agent-run / diff / trace / 快照 / 军团 / 工单 / 邀请令牌 / 聚焦盒」等内部词换成用户能懂的说法;枚举未映射时不再把原始 id 渲染给用户;12 处error.message顶替文案改为产品句在前、原始报错作次级信息。docs/workhub/00-overview/glossary-dejargon.md:任务 / 小队 / 变更申请 / 还原点 / 执行 / 写入时间线 / 快捷入口 / 邀请码,Rust 通知层用词与页面一致。agent-run/agent run写法、词典文件里的纯英文字面量也扫;门禁自测 29 + 5 条。禁词棘轮基线 19→62(新增 43 条全在 web/ui/api,交网页批处理),文案 locale 基线 3669→3659。expected 基线 diff 摘要(
pnpm gen:expected幂等)M6:只新增 5 份
apps/api/expected/mcp-tool-*,既有零改动。插件阶段 2:
plugin-tool-spec.expected.json改为两档各两条(差异实质两格:read_only档下echo的side_effectexternal_effect→none、min_scope…:external_effect→…:read;write_note两档都是external_effect,即「自述只能降不能抬」的逐字节证据);plugin-tool-model-view.expected.json多一个model_tool_read_only_trusted,角色可见性按信任级别 × 工具展开四张表。plugin-tool-engine-request/plugin-tool-sanitized零变化。M2:模型可见文本零变化。
验证
pnpm -r typecheck全 Done;desktop-webview 1704 / cuu 50 / api 2155 / ui 261 / web 168 / plugin-host 53 / mcp-client 137 / db 511 / contracts 196 / api-client 46 / scripts 48 全过;cargo fmt / test 198 / clippy 三门绿。qa:plugin-smoke(真守卫)通过。🤖 Generated with Claude Code