2026-06-11 02:03:00 +08:00

151 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# v0.5.8
## 新功能
- **逆向工程插件 v0.4.2**(`plugins/reverse-engineering`)。仓库自带的 marketplace 现在收录一个多平台
逆向工具箱,一键安装即可获得 7 个 MCP 服务器、1 个编排 agent、11 个 skill、2 个 slash 命令:
- **静态分析**:Ghidra(pyghidra-mcp)/ radare2 / JADX / apktool。覆盖 PE / ELF / Mach-O,以及
无 header 的固件 blob(路由器固件、Cortex-M flash dump、ECU dump 等)。多架构:x86/x64、ARM
(含 Cortex-M Thumb-only)、AArch64、MIPS、PowerPC(含 VLE)、Motorola 68k / ColdFire、SuperH、
RISC-V,以及 AVR / MSP430 / 6502 / Z80 等小架构
- **动态分析**:Frida(Java/ObjC hook + Stalker trace)/ GDB(单步、硬件断点、watchpoint、跨架构
via `gdb-multiarch + qemu`)/ LLDB(Apple 平台单步 + ObjC method hook)。`dynamic-debug-overview`
skill 让 agent 自动选车道
- **编排**:`reverse-engineer` agent 走 triage → static → 可选 dynamic → report 流程,产物落在
`${ARTIFACT_DIR}/<sample-id>/`(默认 `artifacts/re-runs`)
- **slash 命令**:`/reverse-engineering:triage <path>``/reverse-engineering:report <sample-id>`
- **配置**:`GHIDRA_INSTALL_DIR`(可选,Ghidra 安装目录)、`ARTIFACT_DIR`(产物输出位置)
- **规则**:对样本只读,不向外推任何样本(无 VT / no malware-bazaar),不破解商业授权,Frida 只跑
用户授权过的目标,纯静态结论可信度上限封在 medium
桌面端「设置 → 插件」添加本仓库 `plugins/` 目录作为 marketplace 即可启用。详见
`plugins/reverse-engineering/README.md`
- **零成本会话接力**。新建会话欢迎页"最近活动"卡片新增"从这里继续"按钮。点击后服务端用 LLM
生成上一个会话的两层摘要(主线 + 最新进展)落盘缓存,通过 `--append-system-prompt` 注入到新
会话的 system prompt,再自动发一条短的 trigger message 让 AI 接续。前端展示生成进度阶段
("读缓存 → 生成摘要 → 启动会话"),完成后会话头部出现 `↗ 已接续 (N tokens)` 小芯片。摘要生成
失败时静默降级到原有的 zero-token textarea 预填路径。摘要 token 上限受 `CLAUDE_CODE_HANDOFF_MAX_TOKENS`
(默认 1500)和 `CLAUDE_CODE_HANDOFF_INPUT_CHARS`(默认 80000)约束,WS handler 缓存命中后不重生成。
- **欢迎任务卡片项目感知**。原本写死的 4 个起始 prompt 现在按项目状态动态填充:
- "PR 预合并审查"会替换成实际的 `git.defaultBranch`,develop 分支上不会再让 AI 对着 main 做审查
- "排查失败的测试"和"补单元测试"会从最新的 dirty files 列表里挑一个真实文件路径(测试文件正则 + 源码文件正则,跳过锁文件 / 构建产物 / 二进制),自动填进 prompt
- 每张卡片的 `title=` 属性都是完整解析后的 prompt,鼠标悬停就能预览要发送什么
- 第 4 张卡 `explainCode` 重命名为 `understandProject`,prompt 改成读 CLAUDE.md / AGENTS.md / README + 列技术栈和顶层目录的项目全景介绍
- 服务端 `recent-activity` 接口新增 `dirtyFiles[]` 字段(`git status --porcelain=v1 -z` 解析,按 mtime 倒序,最多 20 个),走原有 TTL 缓存
- **伪 tool_use 检测与 provider 兼容追踪**。某些第三方 Anthropic 兼容网关(mimo / lgfzer / 部分代理)
不转发原生 tool_use block,模型只能在 `content_delta` 里输出 XML 风格的 `<tool_use ...>{...}</tool_use>`
当文本流过来,渲染后变成 `<tool_useid="..."` 那样的乱码,而且模型自己以为调用成功还会写"Done."。
这次三层防御:
- 桌面端 `desktop/src/lib/fakeToolUseDetection.ts` 用正则提取这种伪块(闭合 / 流式半开 / 多块连续 /
属性顺序互换 / 引号变体 / 自闭合 / 围栏代码块内的合法示例不误伤),`AssistantMessage` 在交给
`MarkdownRenderer` 前清掉,`copyText` 也走净化版本
- 新组件 `FakeToolUseNotice` 在气泡上方渲染灰色提示卡:"模型尝试用 XML 文本块调用 `Bash`,但当前 provider
似乎不转发原生 tool_use,实际并未执行",让用户不会误信后续"Done."
- 新 store `providerCompatStore` 按 provider id 计数(localStorage 持久化),累计 3 次伪 tool_use 弹一次
warning toast 建议切换 provider;Settings → Provider 列表上对应 provider 显示"工具调用异常"红色徽标,
编辑该 provider 配置后会自动清零(给新配置一次机会),阈值之后只增不弹,不打扰
## 修复
- **服务端检测 + 自动回退 thinking 不兼容 provider**。某些第三方 Anthropic 兼容网关(典型:基于
AWS Bedrock 的代理)会把 cc-haha 发的 `thinking` 字段塞进 Bedrock 的 `additionalModelRequestFields`,
目标模型不认识就返回 400 拒收(报错信息含 `additionalModelRequestFields not supported` /
`thinking is not supported` 等)。这次:
- 服务端 WS handler 在转发 sidecar 的 api_error 消息时新增 `detectThinkingIncompatMessage` 模式
匹配,命中后:
1.`providerService.markThinkingIncompatible(id, reason)``thinkingIncompatible: true`
和 reason 写进 `~/.claude/cc-haha/providers.json`(单条 reason 最长 500 字)
2. 通过 `enqueueRuntimeTransition` 调度一次 sidecar 重启(走的是和 set_runtime_config 同一条
优雅重启路径,不会打断进行中的流式响应)
3. 推一条新的 WS 消息 `provider_compat_event { providerId, kind: 'thinking_incompatible',
reason }` 给前端
- `buildProviderManagedEnv` 看到 provider.thinkingIncompatible === true 时自动注入
`CLAUDE_CODE_DISABLE_THINKING=1`,sidecar 重启后**所有后续请求**都不再发 thinking 字段
- 前端 `providerCompatStore` 新增 `thinkingIncompatibleProviderIds: Set<string>` 维度
(localStorage 持久化),收到 `provider_compat_event` 后弹一次 toast 告知用户已自动回退;
Settings → Provider 列表对应行渲染"思考不兼容"红色徽标(独立于"工具调用异常"徽标,可同时
出现)
- 用户**编辑**该 provider 任何字段并保存 → `updateProvider` 服务端清掉 `thinkingIncompatible`
+ reason,前端 `clearProvider(id)` 同步清两个维度的 store。给改完配置的 provider 一次新机会,
再次出错会重新触发流程
- 检测的正则故意收得很紧(只匹配 `additionalModelRequestFields` / 明确的 thinking 拒绝短语),
避免误伤无关 4xx 把 thinking 永久关掉
- **会话接力不再留下空白会话**。当用户从 sidebar 顶部点过"新建会话"创建了一个空白 sessionA(然后
关掉 tab 留在 sidebar),回到欢迎屏点"从这里继续"时,之前的实现会再 createSession 一个新会话
sessionB,sessionA 变成孤儿空白会话。现在 EmptySession.onAutoHandoff 在 createSession 前先用
`pickReusableEmptySession` 找同 workDir 下消息数=0 且不是 previousSessionId 的最新空白会话,有
就 openTab 复用它,没有才创建新的。新增 `desktop/src/lib/sessionReuse.ts` + 7 个单测覆盖
workDir 过滤、消息数过滤、excludeSessionId、null workDir 防御等边界。
- **会话接力摘要现在带最后 12 轮原文(可调)**。原本的两层摘要 main + recent 是 LLM 抽象出来的,
容易丢失"用户上一句具体问什么"、"AI 上一次回复到哪了"的真实措辞。现在 `sessionSummaryService`
生成摘要时额外保留原会话最后 12 轮(默认)的 USER:/ASSISTANT: 原文,每条截到 400 字、整体 cap
8000 字,新字段 `recentRaw` 落进缓存,`formatHandoffSystemPrompt` 在 main+recent 之后追加这段
到接续 system prompt 里。可通过环境变量 `CLAUDE_CODE_HANDOFF_RAW_TURNS`(050,默认 12)和
`CLAUDE_CODE_HANDOFF_RAW_CHARS`(50030000,默认 8000)调节。0.5.7 旧缓存没有 `recentRaw` 字段,
formatter 自动跳过原文段,完全向后兼容。
- **服务端模型上下文不再示范错误格式**。`specialistRouter.ts` 早就警告过 `key="value"` 属性式片段
会让网关模型把 tool_use 退化成 XML 文本,但还有 3 处反复给模型喂 `subagent_type="verification"`:
`verification_gate_reminder`(messages.ts)、TodoWriteTool 的 verification 提醒、TaskUpdateTool 的
verification 提醒。改成散文形式("set the subagent_type parameter to verification"),从源头降低
伪 tool_use 概率。新增 `noKeyValueNudges.test.ts` 锁住这 3 处,以后改回属性形式立即挂 CI。
## 范围
- 思考不兼容自动回退:`src/server/types/provider.ts`(SavedProvider schema +
`thinkingIncompatible` / `thinkingIncompatibleReason` 字段)、
`src/server/services/providerService.ts`(`markThinkingIncompatible` 方法 + `updateProvider`
自动 re-arm)、`src/server/services/providerRuntimeEnv.ts`(`buildProviderManagedEnv` 注入
`CLAUDE_CODE_DISABLE_THINKING=1`)、`src/server/ws/{events,handler}.ts`(新 ServerMessage
`provider_compat_event` + `detectThinkingIncompatMessage` + `notifyThinkingIncompatIfMatches`)、
`src/server/__tests__/{providers,provider-runtime-env}.test.ts`(7 + 2 新单测)、
`src/server/ws/thinkingIncompat.test.ts`(6 新单测);桌面端
`desktop/src/types/{provider,chat}.ts`、`desktop/src/stores/providerCompatStore.ts`(新增
`thinkingIncompatibleProviderIds` 维度 + `recordThinkingIncompatible` action +
`hasProviderThinkingIncompatible` helper)、`desktop/src/stores/chatStore.ts`(消息分发新增
case)、`desktop/src/pages/Settings.tsx`(新"思考不兼容"徽标)、5 语种 i18n 新增 3 条 key、
`desktop/src/stores/providerCompatStore.test.ts`(新增 6 单测)。
- 会话接力修复:`desktop/src/lib/sessionReuse.ts`(空白会话复用 picker)、
`desktop/src/lib/sessionReuse.test.ts`(7 单测)、`desktop/src/pages/EmptySession.tsx`
(onAutoHandoff 接入 picker)、`src/server/services/sessionSummaryService.ts`(`recentRaw`
字段 + buildRecentRawSlice + formatHandoffSystemPrompt 注入)、
`src/server/services/sessionSummaryService.test.ts`(8 单测)。
- 逆向插件:`plugins/.claude-plugin/marketplace.json`、
`plugins/reverse-engineering/`(plugin.json / mcp/servers.json /
agents/reverse-engineer.md / 11 个 SKILL.md / 2 个 slash 命令 / scripts/{dev-link,smoke,validate}.ts /
README.md)。
- 会话接力:`src/server/services/sessionSummaryService.ts`(LLM 双层摘要 + 磁盘缓存)、
`src/server/api/sessions.ts`、`src/server/ws/handler.ts`(`set_handoff_summary` 路径)、
`desktop/src/components/welcome/RecentActivityCard.tsx`、`desktop/src/api/projects.ts`、
`desktop/src/stores/sessionRuntimeStore.ts`(handoffInfo)。
- 欢迎卡片:`desktop/src/components/welcome/WelcomeTaskCards.tsx`(resolver 模式 + 内部 fetch)、
`desktop/src/api/projects.ts`、`desktop/src/pages/{EmptySession,ActiveSession}.tsx`、
`src/server/services/projectActivityService.ts`(dirtyFiles 派生)、5 个语言的 i18n 模板参数化。
- 伪 tool_use 检测:`desktop/src/lib/fakeToolUseDetection.ts`、
`desktop/src/stores/providerCompatStore.ts`、
`desktop/src/components/chat/{FakeToolUseNotice.tsx,AssistantMessage.tsx}`、
`desktop/src/pages/Settings.tsx`(badge + clear-on-edit)、
`src/utils/messages.ts`、`src/tools/{TodoWriteTool,TaskUpdateTool}/`、
`src/utils/noKeyValueNudges.test.ts`。
- i18n:5 个语言新增会话接力、欢迎卡片参数化 prompt、providerCompat 共 10+ 条 key。
## 验证
- 单元测试:`fakeToolUseDetection.test.ts` 14 / `providerCompatStore.test.ts` **14**(原 8 + 6 新增
thinking-incompat) / `AssistantMessage.faketooluse.test.tsx` 6 / `EmptySession.test.tsx` 22 /
`sessionRuntimeStore.test.ts`(含 handoffInfo)/ `noKeyValueNudges.test.ts` 3 /
`sessionReuse.test.ts` 7 / `sessionSummaryService.test.ts` 8 全部通过 ✅
- 服务端 `bun test src/server/{ws/thinkingIncompat,__tests__/providers,__tests__/provider-runtime-env,
utils/verificationGate,utils/noKeyValueNudges}.test.ts src/tools/AgentTool/specialistRouter.test.ts`:
6 + 87 + (provider-runtime-env 新 2 单测) + 31 全部通过 ✅
- `cd desktop && bun run lint`:tsc --noEmit 通过 ✅
- 服务端 `bun test src/utils/{verificationGate,noKeyValueNudges} src/tools/AgentTool/specialistRouter`:
31 个测试通过 ✅
- 浏览器 MCP 端到端:在 `feat/welcome-cards-polish` worktree 下,4 张卡片正确替换为
`feat/welcome-cards-polish` 分支名,脏文件 `desktop/src/pages/EmptySession.test.tsx` /
`desktop/src/pages/ActiveSession.tsx` 自动填进 testPath / filePath 槽位,点击后撰写框正确预填 ✅
- 会话接力 MCP 端到端:`feat/session-handoff-summary` 分支生成两层摘要,新会话头部出现
`↗ 已接续 (N tokens)` 芯片,AI 首条响应直接基于摘要继续,不再要求用户重新解释上下文 ✅
- 逆向插件:本次发布未运行端到端 smoke。校验入口在 `plugins/reverse-engineering/scripts/smoke.ts`
(注册 marketplace → enable → `/api/plugins/update` + `/reload` → 断言版本号、组件计数与磁盘源
一致),需服务端 + vite 起来后手动跑 ⚠️ pending