Skip to content

需要支持下OpenCode V2 #172

Closed
Closed

Description

@AAEE86
No description provided.

Activity

  1. lehhair commented on Sep 28, 2026

    @lehhair
    Owner

    是该支持了,工作太忙,我还在用oc v1

  2. AAEE86 commented on Sep 29, 2026

    @AAEE86
    Author

    是该支持了,工作太忙,我还在用oc v1

    工作量有点大,还是大佬来做吧

    OpenCode V2 迁移计划

    状态:规划中(未开工)
    目标环境:opencode v2.0.16(本机实测)、@opencode/client 2.0.19
    当前状态:opencode v0.6.46 对接 V1 API,依赖 @opencode-ai/sdk ^1.16.0(实际安装 1.4.1)
    决策:只支持 V2,直接切换,不保留 V1 兼容分支(详见 §9 决策记录)
    文档来源:https://opencode.ai/v2/docs/、https://opencode.ai/v2/openapi.json(113 条路径 / 245 个 schema)


    目录

    1. 背景与结论
    2. 现状:项目如何接入 OpenCode
    3. V2 五个层面的变更
    4. 完整端点对照表
    5. 消息模型变更(最大改动)
    6. 事件流变更
    7. 文件改动清单
    8. 分阶段实施计划
    9. 决策记录
    10. 开工前必须验证的事项

    1. 背景与结论

    1.1 为什么要做

    本机 opencode 已升级到 v2.0.16,而 OpenCodeUI 仍对接 V1 API。V2 是一次有意为之的破坏性升级,官方文档明确说明:

    V2 有三处有意的破坏性变更:插件 API、服务端 API 与客户端、终端客户端配置。
    集成方若调用 V1 服务端 API,必须迁移到 V2 API。

    也就是说:配置文件、agent、命令、skill 都还能用,唯独「界面程序怎么跟 opencode 说话」这套协议被换掉了 —— 而这恰好是本项目的核心依赖。

    1.2 结论

    属于中等偏大的重构,主要难点有二:

    # 难点 影响面
    1 接口全部重命名(统一加 /api 前缀,十余个端点改名或删除) src/api/ 约 20 个文件
    2 消息数据结构被推翻({info, parts} 两层 → 扁平联合 + 游标分页) 类型、转换层、渲染组件、store、事件

    有利条件:

    • 项目没有自己造轮子,直接使用官方 SDK,迁移路径清晰
    • 配置全部走 HTTP,不读 opencode 的数据库 / auth.json / cli.json / opencode.json 文件本体 → 这部分零改动
    • src/types/api/ 下 16 个文件是 SDK 类型的转发,SDK 换包后自动跟随
    • V2 仍支持 Basic Auth(实测 401 + www-authenticate: Basic realm="Secure Area")→ 鉴权层基本不动

    2. 现状:项目如何接入 OpenCode

    2.1 架构

    【请求通道】
    React 组件/hooks ─► src/api/* ─► getSDKClient() ─► @opencode-ai/sdk ─► HTTP ─► opencode serve
                                         ▲
                              baseUrl + Basic Auth + directory 参数
                              (Tauri 用 plugin-http fetch 绕 CORS)
    
    【事件通道】
    opencode serve  GET /global/event (SSE)
       ├─ 浏览器:fetch + ReadableStream + 手写 SSE 解析器
       └─ Tauri:invoke('bridge_connect') → Rust reqwest 透传 → Channel 回传
            └► events.ts: 解析 + delta 合并 + 断线重连 + 代次防串扰
                  └► useGlobalEvents → messageStore → useSyncExternalStore → React 重渲染
    
    【启动流程】
    main.tsx → invoke('detect_opencode_binary') → invoke('start_opencode_service')
             → Rust spawn `opencode serve` → 解析 stdout 拿 URL → 建立连接
    

    2.2 关键事实

    项 现状
    SDK @opencode-ai/sdk,package.json 声明 ^1.16.0,实际安装 1.4.1(不一致)
    类型来源 src/types/api/* 共 17 个文件,16 个是 SDK 类型 re-export;项目内无任何 codegen 配置
    状态管理 自研 store 类 + useSyncExternalStore(无 zustand/redux)
    Rust 侧职责 spawn opencode serve、健康检查、SSE/WS 透明代理、WSL 管理
    Rust 数据库访问 无(不碰 SQLite / auth.json / cli.json)
    版本探测 无(ServerHealth.version 仅用于 UI 展示,无能力分支)
    历史兼容 shim 5 处(见 §9.3)

    2.3 ⚠️ 已存在的隐患(与本次迁移无关,但应先修)

    1. 依赖不一致:package.json 声明 ^1.16.0,package-lock.json 锁 1.16.0,但 node_modules 实装 1.4.1
    2. 存在会崩溃的调用:src/api/pty.ts:50 调用 sdk.pty.shells(),该方法在 1.4.1 中不存在
    3. Docker 不锁版本:docker/Dockerfile.backend:102 和 docker/backend-entrypoint.sh:34 拉取 releases/latest,很可能已经装成 V2,处于风险中

    3. V2 五个层面的变更

    3.1 客户端包更换

    V1(现在) V2(目标)
    包名 @opencode-ai/sdk @opencode/client
    版本 ^1.16.0(实装 1.4.1) 2.0.19
    入口 createOpencodeClient() OpenCode.make({ baseUrl, headers, fetch })
    返回值 { data, error, request, response } 需 unwrap() 直接返回数据
    流式事件 手写 fetch + SSE 文本解析器 client.event.subscribe() → async iterable
    浏览器兼容 ✅ ✅(官方说明主入口是浏览器兼容的)
    自定义 fetch ✅ ✅(Tauri 的 plugin-http 可继续注入)
    // V2 用法示例
    import { OpenCode } from "@opencode/client"
    
    const client = OpenCode.make({
      baseUrl: "http://127.0.0.1:4096",
      headers: { authorization: `Basic ${btoa(`${user}:${pass}`)}` },
      fetch: tauriFetch,              // Tauri 环境注入,绕 CORS
    })
    
    const session = await client.session.create({ location: { directory: "/workspace" } })
    await client.session.prompt({ sessionID: session.id, text: "..." })
    
    for await (const event of client.event.subscribe()) { console.log(event.type) }

    @opencode/client/service 另提供 Service.discover()/ensure()/headers(),用于管理本地后台服务进程。
    本项目已自行实现进程管理(Tauri spawn),暂不需要,列为可选优化。

    3.2 接口路径全部加 /api 前缀

    详见 §4 完整端点对照表。

    3.3 目录/位置参数传递方式变化

    V1 V2
    GET 参数 ?directory=/path 部分端点仍是 ?directory=,部分改为 ?location[directory]=(deepObject)
    请求头 x-opencode-directory 变为 location 对象
    请求体 directory: string location: { directory: string }
    Session 字段 Session.directory Session.location(Session.Info 含 location / subpath)

    ⚠️ 混合使用:GET /api/session 用裸 directory query,GET /api/config 用 location[directory] deepObject。
    必须逐端点核对,不能一刀切替换。src/utils/directoryUtils.ts 是主要改造点。

    3.4 配置字段格式大改(影响可视化配置编辑器)

    配置文件本身 V2 能读 V1 格式并自动归一化(不重写源文件),所以用户配置不用改。
    但项目的配置编辑器(src/features/settings/components/configEditor*)是按 V1 字段渲染的,需要适配:

    V1 V2
    permission: { bash: {...}, edit: "allow" } permissions: [{ action, resource, effect }] 有序数组
    工具名 bash / task / write / patch shell / subagent / edit
    agent: { ... } agents: { ... }
    agent 字段 prompt / disable / variant system / disabled / model#variant(variant 拼进模型串)
    command / plugin / provider / reference / snapshot / attachment commands / plugins / providers / references / snapshots / media
    mcp: { name: {...} } mcp: { servers: { name: {...} } },enabled → 反转为 disabled
    skills: { paths, urls } skills: ["...", "..."] 一个有序数组
    provider.npm / api / options package(加 aisdk: 前缀)/ settings.baseURL / 拆成 settings/headers/body
    model.id / tool_call / cache_read modelID / capabilities.* / cache.read
    autoshare: true share: "auto"

    3.5 启动与环境变量(待验证)

    Rust 侧当前使用(src-tauri/src/app/commands/opencode.rs、wsl_commands.rs):

    opencode --print-logs --log-level {INFO|WARN} serve --hostname 0.0.0.0 --port <随机端口>
    OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER=true
    OPENCODE_CLIENT=desktop
    OPENCODE_SERVER_USERNAME / OPENCODE_SERVER_PASSWORD
    

    这些是否在 v2.0.16 仍有效,必须实测(见 §10.2)。


    4. 完整端点对照表

    「❌ 删除」表示 V2 无对应端点,功能需移除或另找替代。
    「⚠️ 待验证」表示文档不明确,需实测确认。

    4.1 服务与事件

    功能 V1(当前调用) V2 说明
    健康检查 GET /global/health(Rust 先试 /api/health) GET /api/info 响应变为 {version, pid, urls[], paths:{tmp}},无 healthy 字段
    事件流 GET /global/event GET /api/event SSE 格式与负载全变,见 §6
    断开实例 POST /global/dispose、POST /instance/dispose ❌ 删除 可用 DELETE /api/debug/location 替代(驱逐 location)
    当前路径 GET /path GET /api/location
    重载配置 — POST /api/location/reload 新增

    4.2 会话

    功能 V1 V2 说明
    列表 GET /session GET /api/session 新增 cursor 游标分页、search/project/subpath
    创建 POST /session POST /api/session
    详情 GET /session/{id} GET /api/session/{id}
    更新 PATCH /session/{id} PATCH /api/session/{id}
    删除 DELETE /session/{id} DELETE /api/session/{id}
    会话状态 GET /session/status GET /api/session/active 返回 SessionActive
    拉消息 GET /session/{id}/message GET /api/session/{id}/message 返回结构变了,见 §5
    发消息 POST /session/{id}/message POST /api/session/{id}/prompt 请求体 {text, files, agents, skills, metadata, delivery, resume}
    异步发消息 POST /session/{id}/prompt_async ❌ 删除 改用 /background(后台化阻塞中的工具)
    停止生成 POST /session/{id}/abort POST /api/session/{id}/interrupt
    拷贝 POST /session/{id}/fork POST /api/session/{id}/fork 新增 ForkBoundary
    回退 POST /session/{id}/revert 三段式:POST .../revert/stage → POST .../revert/commit → DELETE .../revert(清除暂存) 交互逻辑要重做
    取消回退 POST /session/{id}/unrevert ❌ 删除
    分享 POST/DELETE /session/{id}/share ❌ 删除 配置层有 share: "auto" 策略,但无 API
    摘要 POST /session/{id}/summarize ❌ 删除 替代:POST /api/session/{id}/compact
    子会话 GET /session/{id}/children ❌ 删除 替代:GET /api/session?parentID=<id>
    待办 GET /session/{id}/todo ❌ 删除 事件侧亦无 todo.updated
    diff GET /session/{id}/diff GET /api/session/{id}/diff
    切换 agent — POST /api/session/{id}/agent 新增
    切换模型 — POST /api/session/{id}/model 新增
    移动会话 — POST /api/session/{id}/move 新增
    查看标记 — POST /api/session/{id}/view 新增
    上下文 — GET /api/session/{id}/context 新增
    收件箱 — GET/PATCH/DELETE /api/session/{id}/inbox[/{inboxID}] 新增(排队/转向投递)

    4.3 权限与提问

    功能 V1 V2 说明
    权限列表 GET /permission GET /api/permission/request 另有 GET /api/permission/saved(已保存规则)
    权限回复 POST /session/{id}/permissions/{pid} POST /api/session/{id}/permission/{rid}/reply 请求体改为 { decision: "once"|"always"|"reject" }
    删除已存权限 — DELETE /api/permission/saved/{id} 新增
    回答提问 GET /question、POST /question/{id}/reply、POST /question/{id}/reject ❌ 删除 → 全新 Form 表单体系 GET /api/session/{id}/form、POST .../form、POST .../form/{formID}/reply、DELETE .../form/{formID}
    待处理表单 — GET /api/form(location 级) 新增

    Form 是全新 UI 能力:支持 string/number/integer/boolean/multiselect/external 六种字段类型,带 when 条件与 metadata。
    当前的「问题回答」组件需要重写为表单渲染器,属于新增功能而非等价替换。

    4.4 模型、配置、项目

    功能 V1 V2 说明
    读配置 GET /config GET /api/config 参数用 location[directory] deepObject
    改配置 PATCH /config ⚠️ 待验证
    改全局配置 PATCH /global/config PATCH /api/experimental/config 标记为 experimental
    读全局配置 GET /global/config ⚠️ 可能无独立端点 V2 只有 location 级 GET /api/config
    模型列表 GET /config/providers GET /api/model + GET /api/model/default
    Provider 列表 同上 GET /api/provider + GET /api/provider/{id}
    可用 shell GET /pty/shells GET /api/config/shell
    Agent 列表 GET /agent GET /api/agent + GET /api/agent/{agentID}
    Skill 列表 GET /skill GET /api/skill
    命令列表 GET /command GET /api/command
    执行命令 POST /session/{id}/command POST /api/session/{id}/command
    项目列表 GET /project GET /api/project
    当前项目 GET /project/current ⚠️ 待验证(可能合入 GET /api/location)
    初始化 git POST /project/git/init ❌ 删除
    更新项目 PATCH /project/{id} PATCH /api/project/{id}
    LSP 状态 GET /lsp ❌ 删除 V2 明确不再运行语言服务器、不提供 LSP 工具、不产生诊断
    格式化器状态 GET /formatter ❌ 删除

    4.5 文件与搜索

    功能 V1 V2 说明
    列目录 GET /file GET /api/fs/list
    读文件 GET /file/content GET /api/fs/read/* 路径在 URL 上(通配)
    文件改动状态 GET /file/status ❌ 删除 替代:GET /api/vcs/status
    写文件 — POST /api/experimental/fs/write 新增,experimental
    内容搜索 GET /find GET /api/fs/find
    文件名搜索 GET /find/file ⚠️ 待验证(可能并入 /api/fs/find)
    符号搜索 GET /find/symbol ❌ 删除 与 LSP 一并移除

    4.6 终端 PTY

    功能 V1 V2 说明
    列表 GET /pty GET /api/pty
    创建 POST /pty POST /api/pty
    详情 GET /pty/{id} GET /api/pty/{id}
    更新 PATCH /pty/{id} PUT /api/pty/{id} 方法从 PATCH 改为 PUT
    删除 DELETE /pty/{id} DELETE /api/pty/{id}
    连接 WS /pty/{id}/connect(带 auth) 两步:POST /api/pty/{id}/connect-token 换令牌 → 再连 GET /api/pty/{id}/connect 连接协议重做
    shells GET /pty/shells GET /api/config/shell
    持久终端 — POST /api/experimental/persistent-pty/* 新增 prototype,暂不接入

    4.7 MCP、VCS、Worktree

    功能 V1 V2 说明
    MCP 列表 GET /mcp GET /api/mcp
    增删 MCP POST /mcp、DELETE /mcp/{name} PUT/DELETE /api/experimental/mcp/{server} 转为 experimental + 路径参数
    连接/断开 POST /mcp/{name}/connect、/disconnect POST /api/experimental/mcp/{server}/connect、/disconnect
    MCP OAuth POST /mcp/{name}/auth*(4 个端点) ❌ 删除 → /api/integration/* 全新体系 GET /api/integration、connect/key、connect/oauth[/{attemptID}][/complete]、connect/command
    MCP 资源 GET /experimental/resource GET /api/mcp/resource 转正
    VCS 信息 GET /vcs GET /api/vcs
    VCS diff GET /vcs/diff GET /api/vcs/diff
    VCS 状态 — GET /api/vcs/status 新增,可替代被删的 /file/status
    VCS 分支 — GET /api/vcs/branch 新增
    评审基线 — GET /api/vcs/base 新增,对 changes 面板有用
    Worktree 列表 GET /experimental/worktree GET /api/worktree 转正(不再是 experimental)
    新建/删除 POST、DELETE /experimental/worktree POST、DELETE /api/worktree
    刷新 — POST /api/worktree/refresh 新增
    重置 POST /experimental/worktree/reset ❌ 删除

    4.8 工具、插件、调试

    功能 V1 V2 说明
    工具列表 GET /experimental/tool、/experimental/tool/ids ❌ 删除 替代:GET /api/plugin(含 Features)
    插件 — GET /api/plugin、POST /api/plugin/check、POST /api/plugin/update 新增
    调试 — GET /api/debug/location、DELETE /api/debug/location/{loc} 新增
    迁移状态 — GET /api/experimental/migration/v1 可用于检测 V1→V2 配置迁移进度
    网页搜索 — GET /api/websearch/provider、POST /api/websearch 新增
    Shell 命令 — GET/POST/DELETE /api/shell、GET /api/shell/{id}/output 新增(位置级)
    插件 RPC — POST /api/rpc/{rpcID}/{method} 新增

    5. 消息模型变更(最大改动)

    5.1 结构对比

    V1 —— 两层结构

    // GET /session/{id}/message → MessageWithParts[]
    { info: Message, parts: Part[] }
    
    // Part 联合(12 种)
    type Part =
      | TextPart | ReasoningPart | ToolPart | FilePart | AgentPart
      | StepStartPart | StepFinishPart | SnapshotPart | PatchPart
      | SubtaskPart | RetryPart | CompactionPart

    V2 —— 扁平联合 + 游标分页

    // GET /api/session/{id}/message → SessionMessagesResponse
    { data: Session.Message.Info[], cursor: { previous: string|null, next: string|null } }
    
    // 消息类型(11 种,按 type 判别)
    type SessionMessageInfo =
      | User | Assistant | System | Skill | Shell | Synthetic
      | Compaction | Idle | AgentSelected | ModelSelected | LocationSwitched
    
    // Assistant 内嵌 content 数组(3 种)
    content: (Text | Reasoning | Tool)[]

    5.2 关键字段变化

    概念 V1 V2
    用户文本 parts[].type === 'text' User.text(直接字段)
    用户附件 parts[].type === 'file' User.files
    用户指定 agent parts[].type === 'agent' User.agents
    模型输出 parts[].type === 'text' Assistant.content[].type === 'text' + text
    推理过程 parts[].type === 'reasoning' Assistant.content[].type === 'reasoning'
    工具调用 parts[].type === 'tool'(内嵌 state) Assistant.content[].type === 'tool'(内嵌 state)
    步骤分隔 step-start / step-finish ❌ 删除(改用 Idle 消息)
    子任务 subtask part ❌ 删除(改用 parentID 会话树)
    快照/补丁 snapshot / patch part ❌ 删除
    重试 retry part Assistant.retry 字段
    压缩 compaction part 独立消息类型 Compaction(Running/Completed/Failed)
    成本/用量 分散 Assistant.cost、Assistant.tokens、Assistant.finish、Assistant.rawFinish
    错误 Message.error Assistant.error + Session.StructuredError

    5.3 新增的消息类型(需要新写渲染分支)

    类型 含义
    system 系统消息
    skill 技能激活记录
    shell shell 命令消息
    synthetic 合成消息(POST .../synthetic 可写入)
    idle 空闲标记(替代原 step 分隔符)
    agentSelected 切换 agent 记录
    modelSelected 切换模型记录
    locationSwitched 切换目录记录

    5.4 影响的代码

    文件 改动
    src/types/api/message.ts Part 联合重写为 Session.Message.Info 联合
    src/api/message.ts 请求参数、buildPromptParams() 重写(text/files/agents/skills)
    src/utils/messageConversion.ts toUIMessage / toUIPart 整体重写
    src/types/message.ts UI 侧模型调整
    src/store/messageStore.ts 数据结构 + 增量合并 + 新增游标分页
    src/features/message/** 所有渲染组件适配(parts 目录、tools renderers)
    src/api/types.ts SendMessageParams 等兼容别名

    5.5 分页

    V1 一次性返回全量;V2 返回 {data, cursor}。

    需要新增:

    • 滚动到顶部时用 cursor.previous 向前加载
    • 与现有「加载历史保持滚动位置」逻辑(fc6ce8e6 fix: preserve scroll position after loading history)协同
    • messageStore 的 MAX_CACHED_SESSIONS = 10 LRU 策略需重新评估

    6. 事件流变更

    6.1 协议

    V1 V2
    端点 GET /global/event GET /api/event
    负载 { directory, payload: { type, properties } } SSE data 字段为 V2EventEncoded(JSON 编码字符串),另有 id / event 字段
    订阅语义 可断线重连 + 代次恢复 仅实时、不回放、不自动重连

    6.2 ⚠️ 官方明确的限制

    订阅是 live-only,没有回放,也没有自动重连。数据源故障会结束当前订阅;恢复后需要重新订阅。
    迟到的订阅者只会收到一个当前的 server.connected 标记,收不到此前的业务事件。

    对本项目的冲击(src/api/events.ts 有 1060 行精巧实现):

    1. 断线重连 + 代次(generation)防串扰 → 必须改为「重连后重新拉一次全量消息」,否则丢消息
    2. delta 合并(coalesceEvents) → V2 无 message.part.delta 事件,需按新事件类型重新设计
    3. 心跳/退避重连(RECONNECT_DELAYS) → 连接管理逻辑保留,但恢复动作要改成"重订阅 + 重拉数据"
    4. @opencode/client 自带订阅:client.event.subscribe() 返回 async iterable,内部共享一条懒连接,最后一个订阅者退出才关闭 → 可以大幅简化手写连接管理

    可选方案:保留现有 fetch+SSE 手写实现(改 URL 和解析),或改用 client.event.subscribe()。
    建议改用官方订阅,能删掉大量手写连接管理代码;但需确认在 Tauri 的 plugin-http fetch 下流式表现正常。

    6.3 事件类型

    V1 的 EventTypes 常量表(src/types/api/event.ts,40 余种)整体需要按 V2 重做,该表被约束为:

    satisfies Record<string, SDKGlobalEvent['payload']['type']>   // SDK 一变,编译即报错

    V2 实际处理的事件集合必须抓真实流量确认(见 §10.3)。

    确定已消失的事件:message.part.updated / message.part.delta / message.part.removed、todo.updated、question.*


    7. 文件改动清单

    🔴 P0 —— 主流程打通

    文件 改动量 说明
    package.json 小 @opencode-ai/sdk → @opencode/client;先修依赖不一致
    src/api/sdk.ts 中 换 client 工厂(保留 Tauri 自定义 fetch + Basic Auth + 缓存失效)
    src/api/*.ts(约 20 个) 大 全部端点路径 + 方法 + 参数(directory → location)
    src/api/events.ts 大 换事件订阅,重写恢复策略
    src/types/api/message.ts 大 消息模型重写
    src/utils/messageConversion.ts 大 转换层重写
    src/store/messageStore.ts 大 数据结构 + 合并 + 分页
    src/utils/directoryUtils.ts 中 formatPathForApi 适配新参数形态

    🟠 P1 —— 功能对齐

    文件 改动量 说明
    src/features/message/** 大 渲染组件按新结构改
    src/hooks/useGlobalEvents.ts 中 事件回调对接
    src/api/pty.ts + ptyBridge.ts 中 改「先换 connect-token 再连」;PATCH → PUT
    src-tauri/src/app/commands/opencode.rs 中 健康检查 → /api/info;启动参数验证
    src-tauri/src/app/commands/wsl_commands.rs 中 WSL 启动脚本参数验证
    src/store/serverStore.ts 小 健康响应无 healthy 字段(checkHealth + 3 处 UI 展示)
    src/api/session.ts 中 revert 三段式、去掉 share/summarize/children/todo/abort

    🟡 P2 —— 周边能力

    文件 改动量 说明
    src/api/config.ts + features/settings/configEditor* 中 配置字段格式大改,编辑器表单重做
    src/api/permission.ts + 权限 UI 中 decision 字段;question → Form 表单渲染器(新 UI)
    src/api/mcp.ts 中 OAuth → /api/integration/* 体系
    src/api/file.ts + 搜索 UI 中 fs 路径;符号搜索移除;file/status → vcs/status
    src/api/vcs.ts、worktree.ts 小 路径改名;worktree reset 移除
    LSP / formatter 相关 UI 小 功能删除,移除入口与状态展示
    src/api/client.ts 小 /config/providers → /api/model + /api/provider

    ⚪ P3 —— 清理

    对象 说明
    openapi_doc.json、openapi_formatted.json 孤儿文件(全仓库无引用),更新为 V2 或删除
    src-tauri/src/app/commands/git.rs 孤儿文件(mod.rs 未声明、未注册、未编译),删除
    历史兼容 shim(5 处) 见 §9.3,本次一并清理
    core.filemode 权限位噪音 容器文件系统会给新写入文件加执行位,可加 .gitattributes 或文档说明

    8. 分阶段实施计划

    建议按阶段提交,每阶段结束时主流程可用。

    阶段 0:环境与依赖修复 🟢 小

    • 修复 package.json / node_modules 版本不一致(1.16.0 vs 1.4.1)
    • 确认 sdk.pty.shells() 缺失导致的当前故障状态
    • 搭建 V2 联调环境:本地 opencode v2.0.16 + opencode serve
    • 抓取 V1 与 V2 的真实事件报文各一份,存入 docs/fixtures/ 作为回归依据
    • 完成 §10 验证清单

    产出:能跑起来,拿到真实数据形状。

    阶段 1:换 SDK + 迁移端点 🟡 中

    • @opencode-ai/sdk → @opencode/client
    • 重写 src/api/sdk.ts(OpenCode.make,保留 Tauri fetch + Basic Auth)
    • 迁移 §4 中无删除项的端点(session 列表/详情、agent、skill、command、project、location、model、provider)
    • 迁移 directory → location 参数
    • src/types/api/* 适配新 SDK 类型导出
    • 健康检查改 GET /api/info(含 Rust 侧 + serverStore + 3 处 UI)

    产出:会话列表、模型列表、配置读取可用。

    阶段 2:消息模型 + 事件流 🔴 大(最难)

    • 重写 src/types/api/message.ts(Session.Message.Info 联合)
    • 重写 src/utils/messageConversion.ts
    • 实现游标分页(向前加载 + 滚动位置保持)
    • 重写 src/api/events.ts 订阅层(改用 client.event.subscribe() 或手写改造)
    • 实现「断线后重订阅 + 重拉全量」恢复策略
    • 重写 EventTypes 常量表与 handleEventForSubscriber
    • messageStore 数据结构与合并逻辑重写
    • 发消息链路:POST .../prompt(含附件/agent/skill 参数)

    产出:聊天主流程可用(发消息、流式回复、工具卡片、历史加载)。

    阶段 3:功能补齐与裁撤 🟠 中大

    • 中止:abort → interrupt
    • 回退:改造为 stage / commit / clear 三段式
    • 权限:/api/permission/request + {decision} 回复 + saved 规则管理
    • Form 表单渲染器(替代 question,六种字段类型)
    • PTY:connect-token 流程、PATCH → PUT、/api/config/shell
    • MCP:OAuth 迁移到 /api/integration/*
    • 文件/搜索:fs 路径迁移、file/status → vcs/status
    • VCS/Worktree:路径迁移
    • 配置编辑器适配 V2 字段(permissions 数组、agents、mcp.servers、providers…)
    • 移除:LSP、formatter、符号搜索、share、summarize、children、todo、prompt_async、worktree reset 的 UI 与代码
    • Rust 启动参数与环境变量验证/调整(含 WSL)

    产出:功能与 V2 对齐。

    阶段 4:收尾 🟡 中

    • 删除 5 处历史兼容 shim(§9.3)
    • 删除孤儿文件(git.rs、openapi_doc.json)
    • Docker:锁定 opencode 版本(不再拉 latest)
    • 全量单测 + 手工回归(多服务器、WSL、Docker 三形态)
    • 更新 README 中的 opencode 版本要求(明确要求 v2)

    产出:可发布。

    工作量参考

    阶段 相对量 粗估(单人)
    0 环境 🟢 小 0.5–1 天
    1 端点迁移 🟡 中 2–4 天
    2 消息+事件 🔴 大 5–8 天
    3 功能对齐 🟠 中大 3–5 天
    4 收尾 🟡 中 2–3 天
    合计 约 2–3 周

    含联调与回归;Form 表单、配置编辑器两块存在不确定性,可能超预期。


    9. 决策记录

    9.1 只支持 V2,直接切换 ✅

    决定:迁移后只支持 opencode V2,不做 V1/V2 双栈兼容。

    理由:

    • 双栈需要启动时版本探测 + 两套端点 + 两套消息模型,代码量约多 30–50%,且长期双份维护
    • V1 已停止演进,opencode 本机已是 v2.0.16
    • 项目当前本就没有版本分支,保持简单符合 KISS

    代价:用户必须把 opencode 升级到 v2,否则无法使用。→ 在 README 明确标注版本要求。

    9.2 不做的事

    • 不保留 /global/health、/global/event 等 V1 端点的双端点兜底
    • 不保留 V1 消息结构的适配层
    • 不迁移配置文件为 V2 原生格式(V2 自动归一化 V1 配置,保持现状即可;配置编辑器只改 UI 渲染)
    • 暂不接入 persistent-pty、plugin RPC、shell、websearch 等 V2 新增能力(YAGNI,需要时再加)

    9.3 要删除的历史兼容 shim

    位置 现状 处理
    src/api/events.ts:578 properties.info ?? properties.message 删除,按 V2 真实字段
    src/api/events.ts normalizeSessionError() 兼容 {name,data} 与 {error:{name,data}} 删除,按 V2
    src/api/pty.ts:27 normalizePty() running: boolean → status 删除,按 V2
    src/components/SessionChangesPanel.tsx:982/1086、src/hooks/useFileExplorer.ts:486 patch 优先、回退 before/after 删除,按 V2
    src-tauri/src/app/commands/opencode.rs:52/66 先试 /api/health 再试 /global/health 改为单一 GET /api/info

    9.4 要移除的功能(V2 已删除)

    LSP 状态 · 格式化器状态 · 符号搜索 · 会话分享 · 手动摘要 · 子会话列表 · 待办事项 · prompt_async · unrevert · worktree reset · file/status(改用 vcs/status)· project/git/init · find/symbol


    10. 开工前必须验证的事项

    这些无法仅凭文档确定,必须实测。完成打勾后再进入阶段 1。

    10.1 依赖

    • 修复 node_modules 与 package.json 不一致(1.4.1 / 1.16.0)
    • 确认 sdk.pty.shells() 缺失造成的当前故障
    • @opencode/client 在浏览器与 Tauri plugin-http 下的流式表现

    10.2 启动参数与环境变量

    • opencode serve --hostname --port 是否仍有效
    • --print-logs --log-level 是否仍有效
    • OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER 是否仍被识别
    • OPENCODE_CLIENT=desktop 是否仍被识别
    • OPENCODE_SERVER_USERNAME / OPENCODE_SERVER_PASSWORD 是否仍生效
    • 启动时 stdout 是否仍打印 http://...(parse_listening_url() 依赖)
    • WSL 启动脚本同样验证

    10.3 事件 payload 真实形状

    • V2EventEncoded 是「JSON 字符串」—— 确认是否双层编码(JSON.parse 一次还是两次)
    • SSE 的 event: 字段取值集合
    • 完整事件类型清单(替代 V1 的 40 余种 EventTypes)
    • 流式增量如何表达(V1 靠 message.part.delta,V2 需确认)

    10.4 接口细节

    • directory vs location[directory] 逐端点核对
    • GET /global/config 是否有替代端点(配置编辑器依赖)
    • PATCH /api/config 是否存在
    • GET /project/current 的替代
    • GET /find/file(文件名搜索)是否并入 /api/fs/find
    • 鉴权:除 Basic 外是否还需 Bearer(@opencode/client 示例用 Bearer)

    10.5 部署

    • Docker 锁定 opencode 版本(当前拉 releases/latest,可能已是 V2)
    • 三形态回归:Tauri 本地 / WSL / Docker

    附录 A:主要参考

    附录 B:本机实测环境

    项 值
    opencode 版本 v2.0.16(/home/coder/.opencode/bin/opencode)
    OpenCodeUI 版本 0.6.46
    V2 client 包 @opencode/client@2.0.19
    V1 SDK(当前) @opencode-ai/sdk 声明 ^1.16.0 / 实装 1.4.1
    V2 鉴权实测 401 + www-authenticate: Basic realm="Secure Area"(Basic 仍可用)
  3. lehhair commented on Sep 29, 2026

    @lehhair
    Owner

    我也看了下,简直是要完全重写

  4. AAEE86 commented on Sep 29, 2026

    @AAEE86
    Author

    我也看了下,简直是要完全重写

    是的 改动太多了😂😂😂 不然我就提PR了

  5. AAEE86 commented on Sep 29, 2026

    @AAEE86
    Author

    我也看了下,简直是要完全重写

    我先用官方Web过渡了 等大佬更新😁

  6. AAEE86 commented on Sep 30, 2026

    @AAEE86
    Author

    我也看了下,简直是要完全重写

    #173 提了个PR 测试不充分 估计还有bug

  7. lehhair commented on Oct 6, 2026

    @lehhair
    Owner

    已更新,可能还有部分我没检查到的问题,确实是个大工程,期待你的反馈

  8. lehhair commented on Oct 6, 2026

    @lehhair
    Owner

    安装0.7.3即可,有问题再开issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions