# Changelog 格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/); 版本号遵循 semver。当前 npm 包名 `@chiro2001/dsh-oc`,尚未发布 registry, 安装/更新走 GitHub 源(`#main` / `#develop`)。 ## [Unreleased] - 修复发布后本地安装 resolver:只解析 dsh-oc codeload SHA,区分 dsh-dcp 等其他包; 无 `rg` 时使用隔离验证过的 grep fallback,扫描失败或 SHA 缺失/歧义时 fail-closed。 ## [0.2.0-rc.4] - 2026-09-11 本候选面向 dsh `>=0.1.5-rc.2`,是 host ABI 破坏性适配:dsh 0.1.5 改了 session-controller 依赖与 assistant 流式事件模型,**不再兼容 dsh 0.1.2 及更早**。 发布/远端不可变标识以最终 GitHub notes 为准。 - 修复 profile 无法启动:dsh 0.1.5 的 `dsh-api-session-controller` 新增硬依赖 `fileUploads`,oc-bridge 现在按顺序插入 headless provider `@chiro2001/dsh-oc/file-uploads`;`bindPrompt` 返回带 `Symbol.dispose` 的绑定, 满足 0.1.5 的显式资源管理(否则 prompt 以 `session/agent-busy` + `TypeError: Object not disposable` 失败)。 - 实时流式移植:已删除的 `assistant/chunk` 会话事件改为全局订阅 `agent/assistant-stream` 帧(attempt `start` 记录 turn/step,`chunk` 复用原 chunk 翻译,`end` 回收 attempt),迟到且无 start 的帧安全丢弃。 - 流式期间的 history 读:0.1.5 不再把 in-flight chunk 写进持久化日志,bridge 将 translator 的 live provisional assistant(id/created/文本块,`time.completed` 未设置)合并进 v1/v2 history 响应,保持 TUI 与 queue-live oracle 的 in-flight 契约(`scripts/e2e-tui-queue-live.sh`)。 - 修复首个回合的 agent/model 标签:live provisional SSE 卡片、prompt 响应 placeholder 与流式中 v1/v2 history 不再硬编码 `build`/`deepseek-chat`,改为使用 会话已记录的 preset 与模型选择;prompt 未携带模型时回退到部署默认模型 (`placeholderSessionOptionsForPrompt`),shell 合成卡片同样优先会话模型。TUI 的 映射默认 agent `build` 由 `applyAgentFromBody` 解析为部署默认 preset,首回合即可 显示实际 preset。 - 历史移植:`SessionHistoryRecord` 的 `chunks` 记录被内嵌 `assistant/message.stream` / `assistant/attempt.stream` 取代;`expandRecord` 把 packed run 还原为 `text-chunks`/`reasoning-chunks`/`tool-call-chunks` 行, 并从 raw `block-start`/`block-end`/`finish` 还原部件时长与 finish reason; `assistant/attempt` 在 live 与历史都不产生 TUI surface。 - 文件工具适配 dsh 0.1.5:`write`/`edit`(`dsh-tool-fs`)在新文件/无 presentation 回放时从调用参数合成 diff,opencode edit 卡片继续携带 `metadata.diff`; `tests/e2e-tui-tools.sh` 的 untracked write 场景改用 `write` 工具。 - 依赖与门禁:devDeps 升到 dsh 0.1.5-rc.2 / cordis 4.0.2,peer 范围收紧为 `>=0.1.5-rc.2`;CI 固定 dsh 0.1.5-rc.2;`pnpm install` 由 pnpm 维护 `pnpm-workspace.yaml` 的 prerelease 例外;replay 语料与 perf session 生成器 更新为 0.1.5 事件形状(session format v3)。 - 恢复语义:0.1.5 不持久化未结算的流式内容,崩溃恢复后该回合可以没有 assistant 消息;`e2e-recovery-crash.sh` 的 oracle 改为“重启图是持久化前缀 + 不伪造崩溃 attempt + 新回合 exactly-once”,并继续断言 idle 与无残留进程。 - 本地门禁全绿:`pnpm typecheck`、438 个单测(23 个文件)、probe 63/63、 `perf smoke (200)`、release artifact audit(干净重建零差异、pack 无绝对路径)、 `scripts/check-all.sh --e2e` 39/39 e2e 首跑 PASSED 且 0 retry;5000 会话压测见 [docs/perf/results-2026-09-11-rc4.md](perf/results-2026-09-11-rc4.md)。 ## [0.2.0-rc.3] - 2026-09-08 本候选面向 dsh `>=0.1.2-rc.1`;发布/远端不可变标识以最终 GitHub notes 为准。 - 修复官方 OpenCode 1.18.18 prompt 的顶层 `variant` 解析:`max`/`off` 在多轮 对话中持续传递,省略 variant 的 Default 会正确回到 dsh 后端默认;session、用户 卡片、live/queued SSE 与 v1/v2 history 的实际模型 effort 保持同步。 - 增加 max/max、off/off、max→Default 的 bridge optimistic-card 回归,以及真实 host API e2e 对 session/history/live model ref 的确定性校验。 - 用户手动 TUI 的 max/off 多轮验证通过;本地确定性 host oracle 进一步断言 provider request body:max 为 `thinking.enabled + reasoning_effort=max`,off 为 `thinking.disabled` 且不携带 `reasoning_effort`。 - 本地完整门禁覆盖 435 个单元测试、63/63 协议探针、perf smoke、工件审计与 39 个 e2e(含真实 TUI、recovery、golden trace),全部首跑通过且无 retry。 - 远端 CI 反馈并修复两项门禁问题:permission TUI 选择状态改为主题无关的 ANSI 前景签名同步;artifact path scanner 在无 `rg` 环境下改为 fail-closed 并提供回归覆盖。 ## [0.2.0-rc.2] - 2026-09-08 本版本面向 dsh `>=0.1.2-rc.1`,包含 Issue #4/#5 及发布前的稳定性收敛。 - 新增官方 OpenCode `!` shell mode:`POST /session/:id/shell` 通过 dsh Agent 的 `runMaintenance` 保证 idle ownership,再以当前 OS 用户身份启动精确 shell 子进程/进程组;不绕过或假称 dsh approval/sandbox。running/completed/error、 abort、busy/idle、`session.idle` exactly-once 和 bridge history 投影均有回归; 完成后通过 `Agent.inject()` 将带 `plugin: dsh-oc` 标记的用户手动命令与 stdout/stderr 注入下一次模型 prompt,但不会自动开启模型回合;模型注入有独立 UTF-8 预算,并在注入失败时把可见警告写入 shell 卡;命令/输出可能包含敏感信息, 会发送给当前配置的模型;新增路由探针、真实 TUI + mock 模型 e2e 与协议说明, 并通过完整 e2e 与用户手动 TUI 验证。 - 修复 `/preset` 切换后 synthetic command result 缺少完成时间,导致官方 TUI 将 `preset switched to ...` 卡片一直显示为 `QUEUED`,直到下一轮对话才清除; 切换卡片现在同时回显切换后的实际模型/variant;增加 bridge 单测、v1/v2 history 与真实 TUI 回归断言。 ## [0.2.0-rc.1] - 2026-09-07 > 本候选面向 dsh `>=0.1.2-rc.1`。PR #1/#2/#3 未原样合入;其有效修复与 > dsh 0.1.2 迁移经过语义重整合,当前分支是独立的 RC 候选。 ### 变更 - bridge 从旧 `apiProxy` envelope 迁移到 dsh 0.1.2 的 `sessionController`、`agentPresets`、`goals`、`sessionSkillCatalog`、 `agents`、`sessions`、`sessionProjections` host services。 - 重整合模型选择、默认模型/preset、队列可见性、approval/question、subagent lineage、history pagination 与 dsh 0.1.2 error ABI;保留稳定的 v1/v2 OpenCode protocol surface。 - 新增 `Last-Event-ID` 有界 SSE ring(事件数与序列化字节双上限),断线游标 命中时只回放缺失事件,淘汰/未知游标回退到 status/control snapshot。 - `/session/status` 改为 dsh `api-session/status` 驱动的内存热路径;冷启动最多 一次有界 `session.list` seed,避免官方 TUI 250ms 等待轮询触发全量持久化 I/O。 - OpenTUI native 临时文件隔离到 `$DSH_HOME/opencode/tmp/tui-`,正常退出 清理、下次启动回收已退出实例;不搜索任意插件缓存,不关闭官方 binary 校验。 - dsh-dcp rc.6 的 `session.events` 兼容 getter 暂时保留,待 dcp 完成 dsh 0.1.2 peer/API 迁移后删除。 - 增加安全默认的 `scripts/monitor-process-io.sh`(observe-only;只允许清理 脚本自己以 `setsid` 启动并校验过的进程组)及 fake attach 空闲回归。 ### 验证 - typecheck、418 个单元测试、协议 probe fixture 全部通过、5000 会话性能测试、 发布工件审计和完整真实 TUI e2e 已通过;rc.1 发布时 probe 基线为 62/62,rc.2 新增 shell route 后的发布基线为 63/63;高风险 flake scan 首跑 30/30,无 retry。 - GitHub CI、full-SHA 冷装、真实 TUI smoke、同 ABI 回滚演练和真实 DeepSeek quick smoke 已通过。发布四元组与哈希见 GitHub prerelease 说明。 ### 发布前收敛 - dsh `subagent` / `subagent_fork` 已转换为原生 OpenCode `task` 卡片,保留 delegation 与 child session lineage;新增真实 TUI Task 导航回归。 - 固定 optimistic user / provisional assistant 的消息时间身份,修复首条回复或 reasoning/tool card 重复渲染;真实 TUI 对工具卡做 exactly-once 断言。 - 收紧 crash recovery 的精确 tmux 父子 PID、run-scoped leftover 检查和 observe-only flake scan,避免按名称操作外部 orphan 进程。 - GitHub e2e workflow 固定 dsh `0.1.2-rc.1`,perf 启动失败即时报告;full-SHA 安装/回滚校验 lockfile 实际 commit,并记录旧 dsh ABI 的联合回滚要求。 - v2 会话摘要/历史按 child label 或 parent-local FIFO 绑定并保留 `metadata.origin`,避免同父同描述的多个 child 被错误复用。 ### 修复 - 用户 prompt 改为以 dsh `mode: 'steer'` 提交:运行中的 turn 在下一个 step 边界就能看到插入的消息,与官方 opencode“追加进会话流、loop 下一步即处理” 的语义一致。此前一律 `mode: 'queue'`(next-turn),插入的消息要等整轮结束 (或 abort)才被模型看到——真实会话 e0336d8b 中,用户给出论文确切标题后 模型继续搜索约 4 分钟才看到;新回归单测锁定 busy 时 prompt 以 steer 送达, 队列相关 e2e(QUEUED 徽标、FIFO、golden trace)全部通过。 - 模型选择不再在首轮后回退到默认模型:TUI 会在会话切换时用“最后一条用户 消息”恢复 prompt 的模型,而 bridge 此前把用户消息(历史与排队回显卡片) 一律标成模型目录首个条目(deepseek-v4-flash),导致第二次提问悄悄切回 flash。现在历史与回显使用会话当前模型(`session.models`)或 prompt body 携带的模型;新增两条回归单测固化“Pro 首轮后不回落 flash”。 ## [0.1.0] - 2026-08-18 ### 新增 - `CONTRIBUTING.md` 自测门槛补充发布/构建产物审计项。 - `.github` 模板升级:bug 报告改用 `dsh-oc --version`;PR 自测清单补充 工件审计与全量 e2e 选项。 - `bridge-router.spec.ts` 追加“翻页间追加消息”游标契约测试:首页后追加新 回合,旧页游标不变、无重复,全量读取恰好包含追加内容一次。 - `bridge-router.spec.ts` 新增分页边界不变量测试:`limit` 切过工具回合时, `after`/`next` 以已转换消息的最旧 seq 为锚点,工具事件(tool/call、 tool/result 不独立成消息)整体落在同一侧页,跨页合并后工具 part 恰好 一次且为 completed。 - `AGENTS.md` 更新 e2e 时长表述(稳定套件已扩展到约 15–20 分钟)。 - `docs/ROADMAP.md` 修正 LATER 说明:`/api/credential/*` 实际存在 dsh `credentials.describe/set/unset` RPC,但 opencode SDK 1.18.18 无消费 路由,维持 LATER 待上游协议出现。 - `docs/RELEASE.md` 增加“当前候选就绪状态(12ca493)”汇总:本地/CI 门禁、 flake/性能/真实模型/安装链路/归因实验证据一览。 - `dsh-oc --version` 在 dsh 缺失时与其他路径一致:退出 127 并输出安装提示 (此前以 1 退出且无提示);新增 bin 单测。 - `docs/PROTOCOL.md` 补齐 v2 路由表:`/api/session/{id}/history` (`after` 独占上界 + `next` 游标语义)、`prompt`/`model`/`agent` 端点, 并注明跨页分页不变量。 - `e2e-tui-turn.sh` 增加工具 part 恰好一次断言:历史中 bash 工具卡片只能 出现 1 次(“动态工具调用两次相同显示”回归项)。 - `e2e-tui-preset-inherit.sh`:对话前 `/preset minimal`(含选择器确认 Enter)后创建新会话,断言新 dsh 会话继承 minimal preset(“对话前 /preset 无法改变 preset”回归项);已入稳定套件,本地 3/3 通过。 - `scripts/update-local-install.sh`:一键把本地 dsh profile 更新到指定 GitHub ref,并校验 resolved commit 与 `dsh-oc --version` 双版本输出。 - 工件审计新增 pack 内容校验:tarball 不得含 `src/`,且 `bin/dsh-oc.mjs`、`lib/index.js`、`lib/bridge/router-entry.js`、 `opencode-version.json`、`cordis.patch.yml` 必须在包内。 - `e2e-queued-order-repro.sh` 稳定性修复:第二条 prompt 改为在工具 part 出现(而非完成后)即发送,保证仍处于 busy 窗口、QUEUED 徽标必然出现; 后续文本加长到 15 段。本地 10/10 flake 扫描通过(48s/次),修复 CI slow-runner 下 “queued prompt not shown” 的失败;queued-followup 黄金 基线已刷新到新场景(180 事件)。 - 5000 会话性能基准记录(commit `609ccd6`):列表/消息/历史/分页/标题补温/ RSS 数据见 docs/perf/results-5000-2026-08-17.md,与 8-15 基线量级一致。 - `e2e-real-llm.sh` 强化断言(round-0002 指出真实回归偏弱):queue probe 现在验证 FIFO 内容顺序(第二条 prompt 是最后一条 user、最后回复含“完成”), 不再只数 user 总数;TUI 键盘输入改为等待投递与回复 idle,并断言恰好新增 一条 user 且面板留档。顺带修复 TUI 阶段 bridge URL 未刷新的潜在 bug, `wait_idle`/计数函数对瞬时 API 失败容错。 - flake 合并基线:6 个最小高风险脚本各 10 次共 60 次首跑全绿(当前 HEAD), 结果见 docs/perf/results-flake-consolidated-2026-08-17.md。 - `e2e-cli-bin.sh` 增加 `dsh-oc --version` 断言:输出必须是 `dsh-oc (dsh )` 双版本格式。 - `SseHub.enqueue`:无客户端连接时缓冲事件,首个 SSE 客户端接入时立即 冲刷(raw 回放/恢复场景的晚连接不再丢事件);新增单测锁定缓冲与即时 广播行为。 - 最小 server 支持 raw SSE 直放模式(`minimal-oc-server.mjs --sse `): 把录制的桥 SSE 事件按原序广播给官方 TUI;复现驱动支持自定义 marker、 事件延迟、CJK 启发式与抓拍时长(`DSH_OC_MINIMAL_*`)。真实会话原始 JSONL 与完整桥 SSE 轨迹的回放均已接入:fixture 回放渲染顺序正确;raw 直放定位到官方 TUI 的 `/global/event` 连接为短暂探针(fixture 模式依赖 连接内流式事件在窗口内送达,外部广播窗口太短),暂不渲染对话,列为后续 实验项;截取关键区段 + 80ms 慢速重放仍未渲染,raw 直放路线关闭(工具 保留);raw 模式下 mux 保持挂起避免桥主动断连。`e2e-real-queued-order.sh` 改为首个 prompt 前开始录全量 `/global/event` 轨迹,真实模型连续三次 复现 wire 前提。 - 官方最小 server 归因 harness:`scripts/minimal-oc-server.mjs` 用桥组件 + 脚本化事件序列(无 dsh、无真实模型)提供完整 OpenCode 兼容面, `scripts/e2e-minimal-server-repro.sh` 驱动官方 1.18.18 TUI attach 并 逐帧分析排队/后续文本顺序;首次运行官方 TUI 渲染顺序正确(后续文本在 排队卡片上方)。桥新增 `src/bridge/router-entry.ts` 构建入口导出 `createBridgeRouter`/`startBridgeServer` 供 harness 使用。 - 真实模型排队错序复现 `scripts/e2e-real-queued-order.sh`(manual,真实 DeepSeek API):工具完成后立即键盘排队第二条 prompt,记录 bridge SSE 时序证据(后续文本 delta 是否在排队用户事件后到达)与流式面板帧; 连续两次运行 `wire_follow_after_queued=1`,面板 45/50 帧回复内容渲染在 排队卡片下方。同时修正 e2e-real-llm/e2e-real-queued-order 的 `DSH_OC_REAL_KEEP_RUN=1` 清理逻辑(此前反向,keep 时反而删除)。 - 候选 opencode 升级 lane `scripts/upgrade-lane.sh`:对候选二进制跑黄金 场景并把归一化 SSE 轨迹与 1.18.18 基线语义差分(`--bin`/`--out`), 同版本验证零差异;版本检查旁路 `DSH_OC_BYPASS_VERSION_CHECK=1` 仅作用于 lane 场景,生产路径仍强制版本一致。 - 错序复现记录 `scripts/e2e-queued-order-repro.sh`:工具+慢流后续文本期间 从键盘排队第二条 prompt,逐帧抓拍官方 TUI 面板顺序(瞬态错序检测),并 冻结第二份 1.18.18 黄金 SSE 基线 `tests/fixtures/golden/queued-followup-1.18.18.sse.jsonl`;mock 驱动连续 运行未观察到瞬态错序,记录作为 renderer/bridge 归因证据。 - 1.18.18 黄金 SSE 轨迹基线:`scripts/e2e-golden-trace.sh` 在真实 TUI 上 跑“工具+后续文本”场景并用观察者 SSE 录轨,`scripts/normalize-golden-trace.mjs` 归一化(去随机 id、绝对时间、机器路径),基线提交到 `tests/fixtures/golden/`;重复运行结构一致,已入 stable 套件,供未来 vendor 升级语义差分。 - 最小 permission e2e `scripts/e2e-tui-permission-mini.sh`:真实 TUI 单次 Allow-once 循环(弹窗 → 批准 → 工具完成 → 恰好一次回复 → 无残留权限), 10–11s;已入 stable 套件,flake 扫描 10/10 全绿。 - flake 扫描第二轮:`e2e-tui-queue-live.sh` 与 `e2e-tui-agent-tab.sh` 各 10 次首跑全绿(此前 CI 偶发 flake 的两个脚本),结果见 docs/perf/results-flake-tui-2026-08-17.md。 - 真实会话 feature 覆盖扫描 `scripts/replay-corpus-manifest.mjs`:只输出 事件类型/特征计数,不接触真实内容;64 个真实会话的 12 个特征已全部被 合成语料覆盖(long-session 由 spec 运行时生成覆盖),报告见 docs/perf/coverage-real-sessions-2026-08-17.md。 - 确定性回放语料(实验 1c):`scripts/build-replay-corpus.mjs` 生成 10 个 结构保持的合成 fixture(reasoning、单/多工具、排队、工具错误、compaction、 打断、goal、plugin-context、session-title、unfinished-turn)到 `tests/fixtures/replay/`;`tests/replay-corpus.spec.ts` 回放审计:无未处理/ 翻译错误、工具调用配对且终态、live 完成态与 durable 一致、durable v1/v2 消息面一致、运行时 10k 事件长会话。 - 预算化 flake 扫描 `scripts/flake-mini-scan.sh`:对最小高风险 e2e 脚本 重复 N 次(默认 10),记录首败与耗时,语义失败立即停止且不重试;恢复 三故障域首轮各 10 次全绿(结果见 docs/perf)。 - 恢复 oracle 增加崩溃语义:`recovery_assert_crash_prefix` 允许重启图是 观察图的完整消息前缀,或等长时最后文本 part 是观察文本的前缀(SIGKILL 落在最后 chunk 落盘边界内属正常崩溃一致性,不是数据丢失)。 - 发布工件审计 `scripts/verify-release-artifacts.sh`(已入 `check-all` 门禁): 从 HEAD 源码干净重建并断言 committed `lib/` 零差异;npm pack 扫描机器 绝对路径;输出 package version、tarball sha256 与 package-tree hash。 - 安装/升级/回滚演练 `scripts/e2e-install-rollback.sh`(manual):从远端 GitHub full SHA 冷装候选并跑真实 TUI smoke,回滚到前版 spec 复跑,同 profile 内探测 re-add 行为;版本 bump 前 in-place 结果仅作命令路径验证。 - 恢复故障域 e2e 矩阵: - `scripts/e2e-recovery-crash.sh`:SIGKILL dsh 在慢流中途,`--session` 重启后断言持久前缀 exactly-once(不丢、不伪造完成)、会话回 idle(必要时 显式取消在途回合)且新 prompt 可继续(20s)。 - `scripts/e2e-recovery-sse-reconnect.sh`:观察者 SSE 断流重连,断言重连 后继续收事件且最终 v1/v2 消息图 exactly-once(13s)。 - mux 重订阅单测:重放的 text-chunks 跨 translator 重建由连接级 replay guard 去重,不重复发送 delta。 - 恢复断言 helper 收敛到 `tests/e2e/recovery-lib.sh`(v1/v2 签名、权威 idle、前缀/完全一致比较),`e2e-recovery-consistency.sh` 复用同一 oracle。 - `GET /api/session/{id}/history`:SDK v2 历史端点(`limit` + `after` 事件 seq 游标),返回 `{ data: SessionMessage[], hasMore, next }`;`after` 为 独占上界(dsh 原生 `beforeSeq`,向后翻页),单页延迟有界;v2 消息转换 新增消息锚点 seq 记录,`after` 为负数返回 400。 - 后台子代理能力开启:`GET /experimental/capabilities` 返回 `{ backgroundSubagents: true }`,并新增 `POST /experimental/session/{id}/background` no-op 成功路由(dsh 会话 服务端常驻,`subagent` 工具默认后台运行)。 - `GET /session/{id}/children`:按 `parentSessionId` 返回 subagent 子会话 列表,配合后台子代理能力供 TUI 子代理树查询。 - `GET /experimental/session`:GlobalSession 列表(支持 search/目录过滤/limit 子集),补齐 experimental 会话列表面。 - `POST /session/{id}/init`:no-op 成功 `true`(dsh 会话创建即初始化)。 - `GET /session/{id}/message/{messageID}`:单条消息查询(v1 转换复用, 未找到返回 404)。 - `POST /session/{id}/permissions/{permissionID}`:SDK v2 权限回复别名 (body 用 `response` 字段),映射到同一 `permissionReply`。 - `GET /api/health`:返回 `{ healthy: true }` 供客户端探活。 - `GET /api/session/active`:返回当前活动会话(`{ data: { [sessionId]: { type: "running" } } }`)。 - `POST /api/session/{id}/wait`:有界轮询等待会话空闲(≤30s,空闲 204)。 - `GET /api/session/{id}/context`:返回 `{ data: SessionMessage[] }`(v2 消息转换复用)。 - `GET /api/session/{id}/event`:按会话过滤的 SSE 事件流(`/global/event` 子集)。 - `GET /api/session/{id}/message/{messageID}`:v2 单条消息查询(`{ data: SessionMessage }`)。 - `GET /api/provider/{id}`:单 provider 查询(`{ location, data: ProviderV2Info }`)。 - SDK v2 权限面补全:`GET /api/permission/request`、`GET /api/question/request` (全局 pending 列表,`{ location, data }`)、`GET /api/session/{id}/permission/{rid}` (单条查询,session 不匹配 404)、`DELETE /api/permission/saved/{id}` (删除 `sessionID:toolName` 内存授权);`GET /api/permission/saved` 输出对齐 SDK `PermissionSavedInfo`(`projectID/action/resource`,保留 `sessionID/grantedAt`)。 - 真实 VCS 面:`GET /vcs`、`GET /vcs/status`、`GET /vcs/diff`、`GET /vcs/diff/raw` 从 stub 升级为真实 git 读取(当前分支、origin 默认分支、staged+unstaged 文件状态与行数、每文件/原始 unified diff;untracked 不进入 status)。 - 工作区文件系统面:`GET /api/fs/read/{path}`(原始字节,越界路径 400, 单文件 5 MiB 上限)、`GET /api/fs/list`、`GET /api/fs/find`(递归查找, 跳过依赖/构建目录并限制结果数);路由匹配新增尾段 `*` 通配支持。 - 生命周期面:`GET /global/health`(`{ healthy: true, version }`)、 `POST /global/dispose` 与 `POST /instance/dispose`(no-op 确认,进程由 dsh 管理)。 - 会话列表真实标题补读:dsh `session.list` 不返回 title 投影,bridge 按会话 补读 history tail 投影并缓存(≤40 全量同步;更大列表不阻塞,后台低并发 补最近 24 个、并发 2),恢复的旧会话也会在退出提示中正确识别。 - Esc 打断/取消:`turn.wait` / `turn.idle` 事件驱动 TUI 运行态;全量 TUI 连按两次 Esc、`--mini` 按一次 Esc 会调用 `session.cancel` 停止在途流。 - `/preset` 新会话继承:最近选择的 agent preset 会应用到后续 `/new` 创建的 会话;切换后广播 `session.updated` 携带新 agent。 - 退出提示说明:opencode 官方退出 splash(全量/`--mini`)无法替换,dsh-oc 在会话有内容时于其下方输出一行说明(session id 属于 dsh,恢复用 `dsh --profile oc --session `);`DSH_OC_DISABLE_EXIT_NOTE=1` 可关闭。 ### 工程化 - CI e2e 每个脚本带 `timeout -k` 执行(默认 300s,`E2E_TIMEOUT` 可覆盖), 挂死套件快速失败并重试一次,不再拖住整个 job。 - CI 失败工件改为打包上传(排除 `node_modules` 与 `work/.git`),上传步骤 限时 5 分钟,避免 `.e2e` 上传挂起数小时。 - `scripts/cleanup-merged-branches.sh` 现在同时枚举本地与远端已合并分支 (dry-run 即可列出 `origin/feat-*`、`origin/chore-*` 遗留), `--apply --remote` 可一键清理。 - `CONTRIBUTING.md`、PR/Issue 模板、分支策略(main 发布 / develop 集成 / 短生命周期功能分支)。 - CI:push 到 `main`/`develop`/`feat-*`/`fix-*`/`docs-*`/`perf-*`/`test-*`/ `chore-*` 自动跑稳定 e2e 套件(`CI_E2E_SUBSET=1`);手动触发全量 e2e + 压测。 - M5 重构:路由注册从 `router.ts` 抽出,并按域拆分为 `src/bridge/routes/{boot,session-v1,session-v2,permission}.ts`; 协议探针自动扫描路由目录。 - `scripts/cleanup-merged-branches.sh`:列出/删除已并入 main 的遗留分支 (默认 dry-run,`--apply` 本地删除,`--remote` 同步删除远端)。 - `scripts/cleanup-e2e-runs.sh`:清理 `.e2e` 下旧的 e2e run 目录 (默认 dry-run,`--keep N` 保留最近 N 个,`--apply` 删除;测试产物可再生)。 - `pnpm run e2e` / `pnpm run e2e:api`:一键跑全量或 API 子集 e2e。 - `scripts/e2e-tui-permission.sh`:真实 TUI 权限/提问 e2e(workspace-write + mock LLM 升级工具调用),覆盖 Allow once、Allow always + 会话内自动放行、 Reject(错误回传且不落盘)、`ask_user_question` 选项对话框,以及 `--mini` 模式下的 once/always+自动放行/reject/question 与单次回复渲染。 - `scripts/e2e-api-permission.sh`:API 权限 e2e 补全(v1 once 不落授权、 v2 always/别名 reject、保存授权不跨会话泄漏、删除后重新询问、question 第二选项回复与 v2 reject、400/404 错误分支)。 - `scripts/e2e-tui-permission-ext.sh`:TUI 键盘面扩展(question 选项 Down 高亮移动、question Esc 取消、permission Esc=reject:standard 直接拒绝、 `--mini` 先弹确认层)。 - `scripts/e2e-tui-mini.sh`:`--mini` 优雅退出(三连 Ctrl+C)后断言 dsh-oc 退出提示可见。 - `scripts/e2e-tui-continue.sh`:种子会话带显式标题,`--continue` 恢复后断言 会话列表返回真实标题(历史“恢复会话无标题”回归项)。 - `scripts/perf.mjs` 新增 `measurements.titleCoverage`:量化列表真实标题覆盖率。 - `e2e-tui-abort.sh`:mini 分支改为等 SSE 出现真实流式增量后再按 Esc,断言确实 打断进行中的流(长 mock 开启 `repeatLast`,修复此前第二次请求被 500 拒绝的假通过)。 - `e2e-tui-queue.sh`:权限弹窗阻塞第一轮时发送第二条 prompt,断言 TUI 显示 QUEUED,批准后第二条按序处理。 - `e2e-tui-queue-live.sh`:慢流进行中从 TUI 键盘发送第二条 prompt,断言 QUEUED 显示后打断并干净退出(“模型运行中无法发送新消息”回归项)。 - `e2e-tui-agent-tab.sh`:Tab 切换 agent 后随 prompt 生效,dsh 会话 preset 真实切换(build → standard)。 - `e2e-tui-abort.sh` 追加 spinner 停止断言:打断后两次捕获不得出现变化的 spinner 帧(“打断后 thinking 一直转圈”回归项)。 - `scripts/e2e-real-llm.sh`:本地真实 LLM 全流程回归(headless 文本+工具、 FIFO 队列顺序、`/goal` 创建、variant 保留、TUI sidebar 与发送、干净退出; 仅本地手动运行,消耗真实 token)。 - README 按评审精简:能力状态前置、移除 cast 录制细节(保留在 AGENTS.md)、 二进制说明只保留“官方二进制”,补充更新命令与 npm 包名说明。 - README 演示改为真实模型录制的 GIF:asciinema cast(`docs/demo/`)经官方 `agg` 渲染成 GIF 嵌入 README(GitHub 不执行 `