- 状态:Draft
- 目的:作为本地
opencode维护 fork 后续开发与修复的统一执行依据 - 适用范围:
session / workflow / recovery / retry / task / notification / sync
当前仓库是本地维护的 opencode fork,目标不是追求功能扩张,而是维持 opencode-xk 在真实使用中的工作流稳定性。
现状有三个事实:
- 本地 fork 与上游存在明显分叉,且核心差异集中在工作流稳定性链路。
- 本地已经形成一套有价值的补丁体系,重点覆盖
session/control、prompt_async交接、global-sync、notification、recovery。 - 上游近期仍在持续修复
retry / session / task / notification / TUI lifecycle,说明当前问题不是个别 fork 私有问题,而是产品主线问题。
本 PRD 的目标不是重写架构,而是在保留本地有效补丁的前提下,持续吸收上游有价值修复,并补齐本地仍未根治的问题。
把本地 opencode fork 稳定在“多轮会话不漂移、异步提示可可靠接管、重试边界正确、子任务不中断主流程、通知不过载、恢复不误伤”的状态。
- 让
prompt_async在 idle 与 busy 两种状态下都能可靠接管会话。 - 保证异步注入消息不会覆盖会话当前 active agent/model。
- 保证 retry 只发生在真正可恢复的错误上。
- 保证 wrapped provider error 与 stream 中断可以进入正确的 retry 边界。
- 保证非法
task_id不会卡死 subagent 创建流程。 - 保证 session 恢复、列表刷新、消息同步、通知派发之间状态一致。
- 不在当前阶段推动大规模架构重写。
- 不以“同步上游全部功能”为目标。
- 不为了代码整洁而删除本地已验证有效的 workflow 补丁。
- 不优先处理与当前主线无关的新功能需求。
当前需要持续解决的问题分为六类:
-
会话控制问题
- 旧任务继续执行
- 最新用户意图被历史 handoff 或 reminder 覆盖
- todo / task summary 干扰当前回合
-
异步交接问题
prompt_async返回成功但会话未真正起跑- 前端 optimistic message 与后端真实接管不同步
- 外部调用方无法确认会话是否已接受消息
-
retry 边界问题
- 非瞬时额度限制被无限重试
- wrapped responses 错误未进入 retry 链路
- Bun stream 中断直接打断 session
-
子任务问题
- 非法
task_id直接导致 subagent 创建失败 - 子任务结果回灌与主任务 handoff 关系复杂
- 非法
-
同步与恢复问题
- session 列表、消息、todo、diff、status 出现陈旧覆盖
- 历史 session 打开时出现
Session not found - 恢复逻辑可能误伤正在运行的 session
-
通知与界面状态问题
- 多窗口重复通知
- idle / error / abort / completion 事件串扰
- TUI 页面切换后的订阅泄漏风险
该项目的直接用户价值不是“多一个功能”,而是:
- 用户发出的最新指令能被当前会话正确执行。
- 会话在长时间运行、重试、恢复、切换页面后仍然可控。
- 子任务、工具调用、通知、恢复链路不会相互放大错误。
- 用户可以稳定地用本地
opencode-xk做真实工作,而不是被工作流问题打断。
以下能力属于本地 fork 的核心资产,后续吸收上游修复时默认保留,不得被覆盖式回退。
关键文件:
packages/opencode/src/session/control.tspackages/opencode/src/session/prompt.tspackages/opencode/src/session/recovery.ts
核心职责:
- 最新真实用户消息优先
- 区分
redirect / pure_continue / mixed_continue / new_request - 清理旧 reminder 对新回合的污染
- 决定 assistant 完成后的
continue / reconcile / exit - 仅在安全状态下执行 recovery
关键文件:
packages/app/src/components/prompt-input/submit.tspackages/app/src/components/prompt-input/pending-state.ts
核心职责:
- 给
prompt_async增加 handoff / acceptance 确认 - 管理 optimistic message
- 管理提交中的 pending 状态
关键文件:
packages/app/src/context/global-sdk.tsxpackages/app/src/context/global-sdk-stream.tspackages/app/src/context/global-sync.tsxpackages/app/src/context/global-sync/event-reducer.tspackages/app/src/context/sync.tsx
核心职责:
- SSE 重连与事件缓冲
- part delta 合并
- revision 防止旧数据覆盖新状态
- session list / message / todo / diff / status 一致性维护
关键文件:
packages/app/src/context/notification.tsxpackages/app/src/context/notification-helpers.ts
核心职责:
- 去重
- 延迟确认 idle
- 避免 error / abort / completion 串扰
prompt_async的前端补偿逻辑仍然存在,但不能替代服务端语义保证。notification / multi-window / TUI listener lifecycle仍需持续监控是否有新回归。
后续开发必须坚持以下原则:
- 优先修工作流正确性,再谈结构收敛。
- 上游修复只吸收正确部分,不覆盖本地稳定性补丁。
retry.ts与message-v2.ts视为高风险区域,所有修改都必须配测试。
-
状态:已完成并验证
-
目标:无效
task_id不再阻止 subagent 启动 -
参考上游:
PR #19328 -
主要文件:
packages/opencode/src/tool/task.tspackages/opencode/test/tool/task.test.ts
-
要求:
- 在复用 session 前先校验
task_id - 无效时直接走创建新 session 分支
- 不破坏当前本地
task metadata与TaskResult结构
- 在复用 session 前先校验
-
状态:已完成并验证
-
目标:weekly/monthly/quota exhausted 等错误直接停止 retry
-
参考上游:
PR #24013 -
主要文件:
packages/opencode/src/session/retry.tspackages/opencode/test/session/retry.test.ts
-
要求:
- 只吸收判断逻辑,不覆盖本地已有 retry 补丁
- 保留本地对 shell interrupt 与 workflow 相关的行为修正
-
状态:已完成并验证
-
目标:provider 返回 wrapped
server_error时进入正常 retry 流程 -
参考上游:
PR #22022 -
主要文件:
packages/opencode/src/session/message-v2.tspackages/opencode/test/session/processor-effect.test.tspackages/opencode/test/lib/llm-server.ts
-
要求:
- 不破坏本地
toolOutput()、active message、tail()等自定义逻辑
- 不破坏本地
-
状态:已完成并验证
-
目标:stream 连接异常视为瞬时错误
-
参考上游:
PR #24076 -
主要文件:
packages/opencode/src/session/message-v2.tspackages/opencode/src/session/retry.ts
-
要求:
- 和 P2-1 同一轮收口
- 统一错误映射与 retryable 模式,不各自叠补丁
-
状态:已完成并验证
-
目标:异步注入消息不覆盖会话当前 agent/model
-
参考问题:
Issue #21728 -
主要文件:
packages/opencode/src/session/prompt.ts
-
要求:
- 当
prompt_async未传agent/model时,优先读取会话最近有效上下文 - 不再默认落回默认 agent 配置
- 当
-
状态:已通过真实 HTTP 服务回归验证,当前不需要额外代码修复
-
目标:
prompt_async noReply=false能稳定拉起 idle session -
参考问题:
Issue #21524 -
主要文件:
packages/opencode/src/server/instance/session.tspackages/opencode/src/session/run-state.tspackages/opencode/src/session/prompt.ts
-
要求:
- 提高服务端侧的“接收成功 = 实际接管成功”一致性
- 不只依赖前端补偿逻辑
-
状态:已完成并通过类型检查
-
目标:避免 TUI 切换页面或 session 后 listener 泄漏
-
参考上游:
PR #24053 -
主要文件:
packages/opencode/src/cli/cmd/tui/app.tsxpackages/opencode/src/cli/cmd/tui/context/*packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
-
要求:
- 仅在确认存在 TUI 长时运行问题时推进
- 不优先于 P0-P3
- 默认采用最小充分变更,不做无关重构。
- 吸收上游修复时优先“手工并入逻辑”,不要直接覆盖本地关键文件。
retry.ts、message-v2.ts、prompt.ts、global-sync.tsx、submit.ts属于高风险文件,改动必须带针对性测试。- 不移除本地
control.ts,除非上游已经提供等价且经过验证的控制层能力。 - 不把前端补偿当作服务端根修;凡是 API 语义问题,最终都应落回服务端处理。
- 传入非法
task_id时,subagent 仍能创建并返回有效task_id。 - 遇到 weekly/monthly/quota exhausted 类错误时,session 停止 retry,并向用户暴露明确错误。
- 遇到 wrapped responses
server_error时,session 进入 retry 流程,而不是直接落成 UnknownError。 - 遇到 Bun stream 中断时,session 自动重试,而不是直接终止。
prompt_async未指定agent/model时,下一轮 assistant 使用当前会话 active agent/model。- idle session 收到
prompt_async noReply=false后能实际开始 assistant turn,而不只是返回 204。 - TUI 组件卸载后不会继续保留旧事件订阅与定时器引用。
以下本地能力不得回退:
- 最新用户消息优先于旧 handoff
- todo reconcile 提醒仍然生效
- optimistic message 与真实消息能正确对账
- 多窗口通知不出现明显重复回归
- session route recovery 仍能处理
Session not found
开发完成后,按最小相关范围先跑针对性测试,再补类型检查。
推荐顺序:
packages/opencode内相关单测packages/app内相关单测bun typecheck(在对应 package 目录执行)
最低测试要求:
test/tool/task.test.tstest/session/retry.test.tstest/session/processor-effect.test.tstest/session/prompt.test.tstest/server/session-flow-routing.test.tspackages/app/src/components/prompt-input/submit.test.tspackages/app/src/context/notification.test.tspackages/app/src/context/global-sync*.test.ts
- 当前工作区关键文件可能存在并行未提交改动,后续开发必须以“读当前文件实际内容”为准,而不是只依赖历史结论。
retry.ts与message-v2.ts同时涉及上游待吸收修复和本地未提交改动,冲突概率高。prompt_async的前端补偿逻辑目前有价值,但不能掩盖服务端根因问题。app-runtime历史上存在一组 layer 裁剪与回补提交,这部分属于技术债,不应在当前阶段继续扩大范围。
按以下顺序推进:
- 维持已完成项的回归稳定性
- 持续关注
prompt_async与 notification 相关真实使用回归 - 如有新的 TUI 长时运行问题,再扩展
#24053同类清理点
当以下条件同时满足时,可认为当前阶段 PRD 达成:
- 本地 fork 的关键 workflow 不再频繁出现“旧任务漂移、假成功、错误重试、恢复误伤”。
- 上游高价值修复被吸收后,没有破坏本地已有稳定性补丁。
- 后续新增问题可以稳定收敛到少数关键文件,而不是在整条链路上随机发散。