feat(coding-agent): OpenCode CLI 适配器,语音 Agent 可选 OpenCode 后端 (Refs #579)#638
feat(coding-agent): OpenCode CLI 适配器,语音 Agent 可选 OpenCode 后端 (Refs #579)#638appergb wants to merge 3 commits into
Conversation
PR Reviewer Guide 🔍(Review updated until commit 331bafe)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
|
@appergb 冲突解决一下 |
PR 合并冲突提示当前状态: 本 PR 与 �eta 已为 CONFLICTING,合并前必须 rebase。 与其他 open PR 的重叠:
建议: 先 rebase 到最新 �eta;若 #688 已合,重点检查 guard.rs 与 dictation_voice_agent.rs。 |
|
作者久不修复,开始认领并修复问题以合入 |
Conflict resolution: - dictation_voice_agent.rs: deleted (beta moved logic to dictation.rs), ported provider dispatch to dictation.rs run_less_computer_once - ipc.ts: deleted (beta split into lib/ipc/ modules), added OpenCodeDetection + codingAgentDetectOpencode to ipc/coding-agent.ts Review fixes (post-merge): - guard: add file-level deny rules (edit/write .env/.git/**/macOS persistence) to build_opencode_guard_config, matching Claude parity - opencode: remove dead cancel.load() call after process exit - dictation: replace hardcoded 'Claude' with provider-agnostic 'Agent' in 3 error/status messages reachable from both backends - commands: add ensure_main_window guard + path-traversal rejection to coding_agent_detect_opencode - dictation: add deny_rule_for_pattern safety gate to approved_patterns filtering, preventing malformed OpenCode allow globs from unapprovable patterns (e.g. 'sudo ' → double-space glob) - mock-data: add missing codingAgentExe field
|
Persistent review updated to latest commit 331bafe |
|
@appergb 需要审核 |
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 适配器,语音 Agent 可选 OpenCode 后端
护栏与参数注入防护(-- 标记)
新增可执行路径偏好配置
Agent 运行器按 provider 分派(Claude / OpenCode)
Diagram Walkthrough
flowchart LR User["用户语音"] --> ASR["ASR 转写"] ASR --> Polish["语音润色(可选)"] Polish --> AgentRun["Agent 运行器"] AgentRun --> Provider{"Provider"} Provider -- "Claude Code CLI" --> Claude["claude -p --settings"] Provider -- "OpenCode CLI" --> OpenCode["opencode run --format json"] Claude --> Stream["流式事件"] OpenCode --> Stream Stream --> Panel["Agent 面板"]File Walkthrough
9 files
添加 CodingAgentProvider 枚举及其解析与默认可执行路径添加 coding_agent_detect_opencode 命令添加 OpenCode 护栏配置函数与高风险命令前缀新文件:OpenCode CLI 适配器(检测、参数、解析、运行器)按 provider 分派运行器,支持 coding_agent_exe 配置添加 coding_agent_exe 字段到 UserPreferences添加 OpenCodeDetection 接口和检测函数添加 codingAgentExe 字段到 TypeScript 接口更新 UI:OpenCode 选项、安装提示、可执行路径输入3 files
导出 opencode 模块、修改可见性注册新命令 coding_agent_detect_opencode导出新类型和函数5 files
更新英文 i18n:OpenCode 提示与可执行路径更新日文 i18n:OpenCode 提示与可执行路径更新韩文 i18n:OpenCode 提示与可执行路径更新简体中文 i18n:OpenCode 提示与可执行路径更新繁体中文 i18n:OpenCode 提示与可执行路径2 files
添加 codingAgentExe 字段到 mock 数据添加 codingAgentExe 字段到测试数据