
【免费下载链接】jetbrains-cc-guiJetbrains Claude Code and Codex GUI Plugin项目地址https://gitcode.com/gh_mirrors/id/jetbrains-cc-gui点击查看免费下载导读本文基于 jetbrains-cc-gui 官方修复记录完整还原 DSHDeepSeek Harnessmodern 线协议 ≥ 0.1.5提问在插件中「弹窗能点、提交无效」问题的根因定位与修复过程——答案id被错误地回填成了问题正文。全文覆盖协议契约、会话级证据、mapQuestionAnswers重写方案、同一 PR 内修复的瀑布流串窗与手动输入联动两个次生缺陷以及可在自己环境中复现核验的完整步骤。读完你将掌握 AskUserQuestion 答案链路从「前端弹窗 → Java 侧 IPC → Node 桥 → DSH host」每一跳的编码契约以及如何借助会话日志、host 探针和密闭 mock 快速定位同类问题。一、问题现象弹窗链路全通最后一跳答非所问用户反馈的原话是在 cc-gui 里没法作答 DSH 提的问题只能到 dsh-web 那边操作虽然弹了问题但答复无效。先给出修复记录的结论弹窗、选项点选、提交、Java 侧 IPC 这条链路是通的坏在最后一跳——Node 桥把答案回填给 DSH host 时答案的id用错了用成了「问题正文」而 DSH 要求回填提问方自己声明的question.id。模型拿到的是一批它从未声明过的 id无法把答案对回到自己的问题上多问题批次、需要自由文本free-text的场景直接读不出有效答复用户于是回到 dsh-web 重新回答。在深入修复方案前先看这一整条链路的构成。提问发起后DSH host 通过 WebSocket 把问题投递给插件的 Node 桥events.js桥调用 requestAskUserQuestionAnswers 经由文件 IPC 把问题交给 Java 侧PermissionServiceJava 侧再渲染到 webview 的AskUserQuestionDialog弹窗用户作答后答案沿原路返回最终由桥以$events/resultmodern 协议或respondlegacy 协议回填 host。链路每一步都有真实会话记录佐证其是通的问题只在答案内容本身。二、根因答案编码在两处语义不一致2.1 两处代码的语义错位环节代码行为前端弹窗与 Claude 共用answerState.ts 的formatAnswers以问题正文为 key 产出答案对象「其他」自由文本被塞进标签数组DSH 桥修复前events.js 的mapQuestionAnswers直接把这个 key 当成 DSH 的答案id发出弹窗组件是与 Claude 共用的一套Claude 的 AskUserQuestion 按问题文本匹配答案所以formatAnswers用q.question问题正文作为答案对象 key并把「其他」自由文本混入标签数组。而 DSH 桥此前直接把这两个 key 当作 DSH 协议中的答案id原样转发——「正文当 id、自由文本当选项」两头都不符合 DSH 的契约。2.2 DSH 协议契约deepseek-ai/dsh-user-questionsAskUserQuestionItem.id「Stable caller-provided question id,echoed in the answer」——必须原样回填这是答案对回问题的唯一依据AskUserQuestionAnswerItem{ id, selected: string[], custom?: string }单选题里custom会取代所选项此时selected必须为空多选题custom可与selected并存。对照 DSH 官方 Web 客户端dsh-client-ui-user-questions它发的永远是{ id: item.id, selected, custom? }。而 cc-gui 桥修复前发出的是{id: 问题正文, selected: [...]}——正文当 id自由文本当选项。三、证据链从真实会话到线上探针3.1 真实会话记录~/.dsh/sessions/**/session*.jsonl.zstd这些日志是多帧 zstd 容器每条记录一帧必须先按帧头结构切分再逐帧解码单次zstdDecompressSync只能拿到 header 帧。对 119 个 transcript其中 36 个含ask_user_question调用的所有工具返回做形状分类结果如下答案形状数量来源id 提问方声明的 id合法72dsh-web 客户端id问题正文本次 bug2cc-gui 插件{answers:[]}2取消 / 兜底调用被中断aborted / interrupted14用户打断轮次两处插件形状的实例都是 cc-gui 驱动的会话session-73f99e35D:\code\广排\psgs-analyze-server2026-09-16session-bacd2ec0D:\code\广排\psgs-server-v22026-09-17以 2026-09-17 那次id: prescheck/otherfix两个问题为例DSH 实际收到的是[ { id: 兜底现在是「静默跳过」…。要不要再加一道前置检查改成主动提示, selected: [只做提示部分生效推荐] }, { id: 另外两个发现要不要我一并修掉可多选, selected: [追溯接口 isReceived 恒为 0String 用了 , …] } ]模型的反应也印证了这一点transcript seq522它只能靠选项文案和顺序硬猜归属并抱怨「你选了那条描述里说要一并告知的选项但没告诉我」——即答复内容不完整、不可核验。用修复后的映射重放同一份真实输入{ answers: [ { id: prescheck, selected: [只做提示部分生效推荐] }, { id: otherfix, selected: [追溯接口 isReceived 恒为 0String 用了 , 批量取消的 findTopByUsinOrderByIdDesc 只取 1 条] } ] }3.2 线上 host 探针排除传输层嫌疑对正在运行的http://127.0.0.1:3080用插件自签的浏览器会话 cookie 发POST /api/$events/result载荷host 响应{args:{clientId,eventId,outcome}}插件实际发送的形状通过解析报Remote event result identifies no active event stream仅因 clientId 是伪造值{clientId,eventId,outcome}裸形状Remote event result requires exactly one plain-object args field结论封包形状是对的answerWaterfall的$events/result调用没有问题坏的只是答案内容。四、修复方案mapQuestionAnswers重写修复落在 events.jsmapQuestionAnswers(answers, questions)增加questions入参按问题正文 → 声明 id反查输出的id一律是提问方声明的 id用该题的options[].label集合区分「选项」与「其他自由文本」命中选项进selected未命中进custom单选题存在custom时selected置空与官方 Web 客户端一致批次里未作答的问题补{ id, selected: [] }镜像 Web 客户端对话框整单取消时仍发{ answers: [] }保住「没有答案」与「全部跳过」的区别若没有任何问题能匹配上legacy host、或非 DSH 形状的旧载荷退回原行为按 key 原样投递不丢人的答案。对应源码events.js中的关键实现byText以问题正文为索引建立反查表optionLabelsOf(question)收集该题声明的选项标签集合selected只保留命中选项标签的项未命中的标签用join(\n)收进custom单选multiSelect ! true且存在custom时selected强制为空——这一条与deepseek-ai/dsh-user-questions协议「单选时 custom 取代所选项」严格对应。matched 0时返回原始 entries保证旧 host 兼容。调用点同步传参bridgeDshQuestionlegacyrespond与bridgeModernQuestionmodern$events/result。从源码可见 bridgeDshQuestion 与 bridgeModernQuestion 都在拿到弹窗答案后调用mapQuestionAnswers(answers, questions)其中questions取自questionRows(event.request)——即 host 原始投递的问题行id 必然来自提问方声明。回归测试events.test.js新增mapQuestionAnswers单元用例——声明 id 回填、单选 custom 覆盖、多选 custom 并存、无选项问题全自由文本、跳过项、取消为空、无匹配时回退。question-bridge.test.js新增模拟 Java 侧 IPC认领请求文件 → 按前端 key 写答案文件断言 host 收到的$events/result值与respond值另断言请求文件逐字携带模型声明的questions。测试注释明确记录了这一回归the dialog keys its answers by question TEXT, and the bridge used to forward those keys as answer ids。验证结果✅node --test ai-bridge/services/dsh/*.test.js114/114 通过修复前 105 新增 9✅node --test全部 ai-bridge 测试759 tests / 756 pass / 3 skipped / 0 fail数字以分支基线feature/v0.5.7为准main与本分支的既有测试数量不同。五、次生风险同一 PR 内一并补修除答案编码外排查中还发现并修复了三个次生风险提交7cbe7ef5/acfa628b/61f355efturn.clientId未就绪时答案被静默丢弃—— ✅ 已修7cbe7ef5answerWaterfall原来在$events未收到ready帧时直接return false日志只在 Node stderrIDE 侧不可见用户在弹窗里答完却被丢弃。现在 approval / question 两个 bridge 都会先有界等待CLIENT_ID_WAIT_MS 3s源码见 events.js 的resolveClientId()接受 id 或取值函数拿到当前 generation 的 clientId 再弹窗等不到就记日志并且不弹窗不会让用户答一个注定发不出去的答案。message-service.js 改为传() turn.clientId等的是实时值而非帧到达时的快照——因为弹窗期间发生重连会铸造新的 clientId必须尽可能晚地读取。dialogToken不匹配被静默吞掉—— ✅ 已修61f355efPermissionHandler.handleAskUserQuestionResponse的静默return拆成两种可诊断分支requestId 不存在 / token 与 pending 不一致各打一条 WARN语义不变仍忽略且保留 pending 请求给复用了同一 requestId 的新弹窗但排查时不再需要靠「缺日志」反推。DSH 的detail/intent被前端丢弃—— ✅ 已修acfa628bnormalizeQuestion.ts 保留detail与归一化后的intentQuestionSection.tsx 用现有MarkdownBlock在选项上方渲染计划正文plan-review 带「计划内容」标题面板限高可滚动provider 现在从permission-ipc一路透传到弹窗两个 bridge 都发dsh标题不再把 DSH 说成「Claude 有一些问题想问你」。仅剩第 4 条作为同类症状线索保留Claude 长驻 daemon 的 routing id 漂移与 DSH 无关孤立 IPC 文件Claude 路径非 DSH%TEMP%\claude-permission\ask-user-question-307c1658-…json2026-09-15 11:49cwdD:\code\广排\psgs-server-v2未被任何 watcher 认领。其 questions 没有id字段是 Claude 的 AskUserQuestion 形状DSH 的id是必填、且经 JSON 无损校验缺 id 的请求根本到不了插件说明是 Claude 侧长驻 daemon 的CLAUDE_SESSION_ID与当时 watcher 的 routing id 漂移。DSH 每轮新起进程、不受此影响仅作为同类症状的另一条线索记录。六、真机IDE 内验证2026-09-17 做了两轮验证。1. 密闭端到端不需要真实 host、不花 token本地 mock DSH hostHTTP /api/remote.mux 真实的 dsh-channel.js →message-service→events.js由脚本扮演 Java 侧与弹窗答案按问题正文做 key、自由文本混进标签——即弹窗的真实形状。同一份脚本分别跑两份 bridge目标host 实收 id结果仓库已修复prescheck, otherfix, cadence, unusedPASS安装目录副本修复前三个问题正文第 4 题整题丢失FAIL2. IDE 内真机一轮15:10:30 插件从 cc-gui 发起 DSH 轮次日志sendToCli providerdsh, cwdD:\code\jetbrains\jetbrains-cc-gui-v2bridge 进程来自已打补丁的安装目录[dsh] Command: …\plugins\idea-claude-code-gui\ai-bridge\channel-manager.js dsh send。sessionsession-2754c72b-235a-41c7-b745-6e8157d655f4模型声明idabc_test3 选项、单选DSH 实收{answers:[{id:abc_test,selected:[A. 选项 A —— 能正常点选]}]}模型随后正确读到答复并汇报「控件工作正常」——id 与声明一致提问→渲染→点选→结构化回填闭环。七、如何在你的环境里复核快速复核不必重新打包pluginDir\ai-bridge\.bridge-version记录的是0.5.6:ai-bridge.hash两者一致时BridgeDirectoryResolver会跳过重新解压因此直接把修复后的 events.js 覆盖到pluginDir\ai-bridge\services\dsh\先备份原文件即可DSH 每轮现开channel-manager.js进程下一轮提问即生效无需重启 IDE。正式发布仍走./gradlew buildPluginpackageAiBridge会重新生成ai-bridge.zipai-bridge.hash。在 cc-gui 里触发一次ask_user_question选择选项并提交。到~/.dsh/sessions/workspace/session/session.v3.jsonl.zstd里看tool/resultid应等于模型声明的 id如abc_test自由文本应出现在custom字段未作答的问题应为{id, selected: []}。修复前这里一定是问题正文。读取技巧该文件每条记录一个 zstd 帧需按帧结构切分后逐帧解码可参考deepseek-ai/dsh-session-persistence-jsonl/lib/index.js#scanZstdFrames。八、同链路第二个缺陷waterfall 未按会话过滤弹错窗口症状cc-gui 里弹窗「串窗口」——别的会话提的问题/审批弹到了当前窗口dsh-web 侧正常因为它按会话作用域订阅。用户视角是「虽然有提问但答复无效 / 不是我这边问的却在我这弹」。根因$events是host 全局流。gateway 把每个 forwarded waterfall 广播给所有$events客户端deliverRemoteEvent遍历remoteEventClients而subscribeModernStreams的$events处理器对approval/request/user-questions/request没有任何归属判断收到就bridgeModernQuestion/bridgeModernApproval→ 弹到当前窗口并且host 用第一个结果 settle waterfall所以插件还会把别的会话的答案抢掉。归属可判定DSH 源码deepseek-ai/dsh-api-session-controller/lib/scope.js明确写着——agent and its session share one id (1:1, same axis; no separate AgentId ...)而 gateway 构造 waterfall 帧时带上agentId: source.context.agentIddsh-api-gateway/lib/index.js因此帧里的agentId就是该请求所属的 sessionId。修复events.js —projectRemoteEventFrame()把帧里的agentId一并带出新增导出waterfallBelongsToSession(agentId, sessionId)缺失agentId的旧 host 按旧行为接受见 events.jsmessage-service.js —$events处理器在进入 approval/question 分支前过滤不属于本会话的请求记一条[dsh] ignoring a … for session … (this turn serves …)后忽略。忽略 ≠ 拒绝该请求在本客户端仍保持 pending由真正拥有它的客户端回答。ready/cancel逻辑不变lastActivityAt改为只在本会话帧上更新避免别家流量掩盖自家静默events.test.js — 帧形状带agentId 归属判定真值表。验证本地 mock host同一次运行同时推「别的会话」与「本会话」两个 waterfallbridge弹窗收到的题目集合结论修复前已安装副本仅有答案映射修复[[foreign], [prescheck,otherfix,cadence,unused]]且foreign waterfall answered here: true弹错窗口并替别人作答修复后[[prescheck,otherfix,cadence,unused]] 忽略日志只处理本会话同一 mock 还断言了答案编码声明 id 回填、custom承载自由文本、未作答补{id, selected: []}。dsh 套件 115/115全量 ai-bridge 760 tests / 757 pass / 3 skipped / 0 fail。影响面提醒approval 走同一条流—— 修复前别的会话的授权请求会弹到当前窗口用户点「允许」等于替别人批准了工具调用。本次过滤同时覆盖两类 waterfall。九、同链路第三个缺陷提问控件里「手动输入与选项联动不上」症状弹窗出现 1/2/3 选项 一行「其他」手动输入时用户反馈「手动输入的没办法联动」——打了字却像没生效。复现真实渲染 点击记录onSubmit实际提交内容操作修复前修复后点「其他」→ 手输 → 提交{Q:我自己的答案}同本来就通点「其他」→ 手输 →再点选项1→ 提交{Q:1. 选项一}输入框消失文本被静默丢弃{Q:1. 选项一}输入框同步清空所见即所交想「选 1 补一句」输入框根本不存在输入框常显一打字自动选中「其他」无选项的自由问答DSH 最常见**必须先点「其他」**才出现输入框不点则提交按钮禁用不渲染「其他」行输入框常显且自动聚焦多选选项1 手输需先点「其他」[1. 选项一,补充说明]根因webview/src/components/AskUserQuestionDialog/QuestionSection.tsx 修复前把输入框写成{isOtherSelected …}—— 只有「其他」被选中才渲染answerState.ts 的toggleAnswerSelection在单选下是clear() add(label)点普通选项会抹掉「其他」标记 → 输入框卸载formatAnswers只在「标记还在」时才带上文本 → 文本静默丢失且没有「打字即选中其他」的联动。修复输入框常显无选项的题隐藏「其他」行并自动聚焦见 QuestionSection.tsx 与 L70-L81打字自动置上「其他」标记单选下按协议替换已选选项因为该题只能携带一个值实现于 useAskUserQuestionState.ts 调用的syncOtherSelection单选点普通选项时清空输入框避免留下「看着还在、其实不会提交」的幽灵文本useAskUserQuestionState.tsformatAnswers改为「文本一定随答案走」单选 custom 覆盖选项、多选 labels custom见 answerState.tscanProceed只要有文本即可提交点「其他」行同 tick 聚焦。真机验证sessionsession-2754c72b-235a-41c7-b745-6e8157d655f4cc-gui 内实际作答两题批次 上一步回退改选{answers:[{id:back_test_q1,selected:[C. 改后的答案]}, {id:back_test_q2,selected:[],custom:正常}]}回退到上一题把 B 改成 C 后提交的是C状态未丢自由文本以custom送达说明手动输入确实随答案提交。测试AskUserQuestionDialog.otherInput.test.tsx10 例全量 webview 182 个测试文件 / 1586 tests 全过npm test含tsc类型检查退出码 0。十、核心文件清单events.jsmapQuestionAnswers重写 两个 bridge 调用点传参projectRemoteEventFrame带出agentIdwaterfallBelongsToSessionmessage-service.js$events按会话过滤 waterfall活动时间只计本会话帧events.test.js新增 5 个映射用例 归属判定用例question-bridge.test.js新增集成用例 4 个QuestionSection.tsx输入框常显无选项时免「其他」行 自动聚焦useAskUserQuestionState.ts打字即选中「其他」单选点选项清空文本文本即可提交answerState.tssyncOtherSelectionformatAnswers文本必随答案normalizeQuestion.ts保留detail/intent使 plan-review 可作答AskUserQuestionDialog.otherInput.test.tsx新增交互回归用例 10 个结语这一轮修复覆盖了同一答案链路上的三处独立缺陷答案编码不符合 DSH 协议id 用错、$events全局流未按会话归属过滤串窗 替答、弹窗手动输入与选项联动失效文本静默丢失。三者合起来回答了「为什么在 cc-gui 里答 DSH 的题无效」的全部表象答非所问、弹错窗口、打了字不算数。对使用者而言升级到含本次修复的版本feature/v0.5.7分支基线即可对集成开发者而言本文的复核步骤与测试用例是理解 DSH modern 线协议答案契约的最小可运行样本。赞分享【免费下载链接】jetbrains-cc-guiJetbrains Claude Code and Codex GUI Plugin项目地址https://gitcode.com/gh_mirrors/id/jetbrains-cc-gui点击查看免费下载相关推荐DSH 提问「答了等于没答」修复实录答案 id 编码、会话级 waterfall 过滤与提问控件联动DSH 提问「答了等于没答」修复实录答案 id 编码、会话级 waterfall 过滤与提问控件联动 本文基于 idea claude code gui 仓库开发工具AI 应用代码智能体Umi-OCR 离线OCR实测500页扫描书一晚上变成可搜索文档Umi OCR 离线OCR实测500页扫描书一晚上变成可搜索文档 最让人头疼的资料一类是截图里的文字一类是没有文字层的扫描书——前者复制不到后者搜不到。OCR桌面应用Ultimate Vocal Remover用 AI 人声分离为翻唱与播客创作人声伴奏轨Ultimate Vocal Remover用 AI 人声分离为翻唱与播客创作人声伴奏轨 Ultimate Vocal Remover 用深度学习做人声分离音频处理人工智能上一篇Tock 在 Raspberry Pi Pico Explorer Base 上的部署指南UF2 烧写、SWD 调试与 OpenOCD 实战下一篇Photoshop图层批量导出终极指南如何快速将图层导出为文件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考