feat(coding-agent): OpenCode CLI 适配器,语音 Agent 可选 OpenCode 后端 (Refs #579)#638
feat(coding-agent): OpenCode CLI 适配器,语音 Agent 可选 OpenCode 后端 (Refs #579)#638appergb wants to merge 2 commits into
Conversation
PR Reviewer Guide 🔍(Review updated until commit 7960ac4)Here are some key observations to aid the review process:
|
|
@appergb 看一下这个参数注入风险 |
注入风险(@H-Chris233 评审):`opencode run` 的 prompt 作为最后位置参数,但之前缺 end-of-options 分隔。以 `-` / `--` 开头的 prompt(语音转写或被 prompt 注入诱导)会被 OpenCode 当作 flag 解析,可绕过护栏(混入 --dangerously-skip-permissions、--dir 改写 工作目录等)。修复:build_opencode_args 末尾追加 `--`,运行器把 prompt 接在其后;新增单测。 可配置路径(@pr-agent 指出之前 hardcode "opencode"):新增 prefs.coding_agent_exe, 语音 Agent 路径据此取 exe(留空回退默认 claude / opencode),检测命令亦用配置路径; 设置「高级 → Less Computer」新增「可执行文件路径」输入;补 5 语言 i18n。
|
Persistent review updated to latest commit 7960ac4 |
) 把 OpenCode 当作与 Claude Code 同类的 coding agent CLI 接入,照既有 coding_agent 适配模式(不另造架构),复用同一套 CodingAgentRequest / CodingAgentEvent / CodingAgentError / 审批护栏链路。 后端: - coding_agent/opencode.rs(新):detect_opencode(opencode --version)、 build_opencode_args(opencode run --format json --model --dir [--dangerously-skip-permissions],prompt 作为 argv)、parse_opencode_json_line (NDJSON:text/tool_use/error;text 块累计,EOF 合成 Completed)、 run_opencode_agent(取消/超时 kill,护栏经 OPENCODE_CONFIG_CONTENT 注入)。 - coding_agent/args.rs:CodingAgentProvider 枚举(claude-code-cli/opencode-cli, 未知回落 Claude)+ from_pref/default_exe。 - coding_agent/guard.rs:build_opencode_guard_config —— 把高风险 bash 前缀翻译成 OpenCode permission.bash deny glob + webfetch deny,审批放行的前缀显式 allow。 - coordinator/dictation_voice_agent: run_less_computer_once 按 coding_agent_provider 分派 Claude / OpenCode 运行器;两路都 fail-closed(护栏生成失败即中止,不裸跑)。 审批拦截探测/重跑放行链路 provider 无关,自动复用。 - commands: coding_agent_detect_opencode 命令(已注册 lib.rs)。 前端: - CodingAgentSection: OpenCode 选项从「即将支持」改为可用 + 选中后探测安装状态并提示。 - ipc: codingAgentDetectOpencode + OpenCodeDetection。 - i18n: opencodeReady / opencodeMissing(5 语言,替换 providerOpenCodeSoon)。 验证:cargo check + cargo test(492 通过)+ npm run build 均通过。 Refs #579 (#579 还含「语音润色模型配置」:prefs 字段已存在但全链路未实现/未接 UI, 转写直接进 agent 未经语音润色模型整理 —— 故用 Refs 不用 Closes。) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
注入风险(@H-Chris233 评审):`opencode run` 的 prompt 作为最后位置参数,但之前缺 end-of-options 分隔。以 `-` / `--` 开头的 prompt(语音转写或被 prompt 注入诱导)会被 OpenCode 当作 flag 解析,可绕过护栏(混入 --dangerously-skip-permissions、--dir 改写 工作目录等)。修复:build_opencode_args 末尾追加 `--`,运行器把 prompt 接在其后;新增单测。 可配置路径(@pr-agent 指出之前 hardcode "opencode"):新增 prefs.coding_agent_exe, 语音 Agent 路径据此取 exe(留空回退默认 claude / opencode),检测命令亦用配置路径; 设置「高级 → Less Computer」新增「可执行文件路径」输入;补 5 语言 i18n。
7960ac4 to
55cc808
Compare
User description
背景
Refs #579。#579 要的「语音快捷键触发 Claude Code / OpenCode Agent」中,Claude Code 后端已随 fast-agent / less-computer 落地,但 OpenCode 后端只有占位:
coding_agent_provider已有opencode-cli选项(标「即将支持」),但后端从不读它、永远跑 claude。本 PR 把 OpenCode 真正接上,照既有coding_agent适配模式实现,不另造架构。改动清单
后端
coding_agent/opencode.rs(新增):OpenCode 适配器,与 Claude 适配器同形、复用同一套CodingAgentRequest/CodingAgentEvent/CodingAgentError:detect_opencode:opencode --version(复用parse_claude_version取x.y.z)。build_opencode_args:opencode run --format json --model <provider/model> --dir <cwd> [--dangerously-skip-permissions];prompt 作为 argv 位置参数(OpenCode 从命令行读,不像 claude 从 stdin)。parse_opencode_json_line:解析 OpenCode NDJSON(text→ Delta、tool_use→ ToolUse、error→ Error);OpenCode 的text是完整文本块且无带 cost 的终局 result 事件,故累计文本、EOF 处合成Completed(cost_usd = None)。run_opencode_agent:取消/超时 kill 子进程;护栏经OPENCODE_CONFIG_CONTENT注入。coding_agent/args.rs:CodingAgentProvider枚举(claude-code-cli/opencode-cli,未知回落 Claude)+from_pref/default_exe。coding_agent/guard.rs:build_opencode_guard_config—— 把高风险 bash 前缀翻译成 OpenCodepermission.bash的 deny glob(如"rm -rf *": "deny")+webfetch: deny,审批放行的前缀显式allow。这是 Claude--settingsdeny 护栏在 OpenCode 的等价物。coordinator/dictation_voice_agent.rs:run_less_computer_once按coding_agent_provider分派 Claude / OpenCode 运行器。两条路径都 fail-closed(护栏配置生成失败即中止,绝不无护栏裸跑)。审批拦截探测 + 重跑放行链路本就 provider 无关,自动复用(OpenCode 重跑时把放行前缀传入 guard builder)。coding_agent/commands.rs+lib.rs:coding_agent_detect_opencode命令。前端
CodingAgentSection.tsx:OpenCode 选项从「即将支持」改为可用;选中 OpenCode 后端时探测安装状态并提示(已安装显示版本 / 未安装提示先npm i -g opencode-ai+opencode auth login)。lib/ipc.ts:codingAgentDetectOpencode+OpenCodeDetection。opencodeReady/opencodeMissing(zh-CN / en / ja / ko / zh-TW;替换原providerOpenCodeSoon)。安全
bypassPermissions在语音路径降级为 acceptEdits 等价(保留护栏);OpenCode 用permissiondeny 高风险 bash + 禁 webfetch,fail-closed。opencode serve+ stdin 方案。测试情况
cargo check(macOS)✅cargo test --lib:492 通过(新增 10 个单测:provider 解析/默认 exe、OpenCode args/stream 解析、OpenCode 护栏 deny/放行)✅npm run build(tsc + vite)✅opencode并opencode auth login;② 设置→Less Computer 选 OpenCode 后端,确认安装提示正确;③ 语音触发一次任务,确认流式输出进聊天浮窗、能落地改动;④ 触发一次高风险命令(如rm -rf)确认被护栏拦截并弹审批卡,Approve 后重跑放行。为什么是 Refs 而非 Closes #579
#579 还含「语音润色模型配置」一项:prefs 字段(
coding_agent_use_voice_polish/voice_polish_model_mode/voice_polish_provider_id/voice_polish_thinking_enabled)已存在但全链路未实现——语音 Agent 当前把原始转写直接送 agent,未经语音润色模型整理,也无对应 UI。该项不在本 PR 范围,故用Refs #579。建议作为 #579 的剩余子项单独跟进。🤖 Generated with Claude Code
PR Type
Enhancement, Tests
Description
OpenCode CLI 适配器([feature] 语音快捷键触发 Claude Code / OpenCode Agent,并支持语音润色模型配置 #579)
Agent 可选 OpenCode 后端
护栏配置双重路径
前端配置与检测提示
File Walkthrough
11 files
Add CodingAgentProvider enum and prefs parsingAdd coding_agent_detect_opencode commandAdd OpenCode guard config builderRe-export opencode module and helpersNew OpenCode CLI adapter moduleDispatch agent runner by providerRegister coding_agent_detect_opencode commandAdd coding_agent_exe preference fieldAdd OpenCodeDetection interface and detect functionAdd coding_agent_exe to UserPreferencesAdd OpenCode detection hint and exe config5 files
Add OpenCode detection i18n keysAdd OpenCode detection i18n keysAdd OpenCode detection i18n keysAdd OpenCode detection i18n keysAdd OpenCode detection i18n keys1 files
Update test default with coding_agent_exe