fix(agents): label forking the same for every agent

The fork row said "Branch Session" on Claude Code and "Fork Session"
everywhere else, on the strength of a source comment claiming "Claude Code
calls it branching". It does not. `claude --help` documents the flag as
`--fork-session`, described as "When resuming, create a new session ID instead
of reusing the original"; the only occurrences of "branch" in its help are an
unrelated git-branch review option. The claim came from otty's own UI wording,
which I mistook for Claude's vocabulary and then wrote into the source as
fact — so the comment goes with the special case rather than being left behind
as a false statement about someone else's tool.

The split was also inconsistent with itself: Grok takes the identical
`--fork-session` flag and was already labelled "Fork Session". Every agent that
has the capability calls it forking — `codex fork`, `--fork-session` on Claude
Code and Grok, `--fork` on OpenCode — so one wording covers all four.

`fork_label` keeps returning `Option<&'static str>`: it is still the UI's single
capability gate (`None` = no verified fork command, no row offered), and
per-agent wording stays expressible should one ever genuinely diverge.

Generated commands are untouched — the existing table test still pins
`claude --resume <id> --fork-session` and the other three verbatim.

Also drops the two doc sentences that promised the per-agent label, and the
stale "Branch Session" mentions left in comments; no occurrence survives
anywhere in the tree.
This commit is contained in:
l0ng-ai
2026-07-29 00:12:08 +08:00
parent 30c8232042
commit a7240f394d
6 changed files with 23 additions and 23 deletions
+9 -7
View File
@@ -265,15 +265,17 @@ impl CLIAgent {
}
}
/// The agent's own word for forking, for menu labels — otty's convention,
/// and the word a user hunting the menu will be looking for. `Some` exactly
/// when [`fork_command`](Self::fork_command) can build a command, so the UI
/// can use it as the single capability gate.
/// The menu label for forking this agent's session — one wording for every
/// agent, because every agent that has the capability calls it forking
/// (`codex fork`; `--fork-session` on Claude Code and Grok; `--fork` on
/// OpenCode). `Some` exactly when [`fork_command`](Self::fork_command) can
/// build a command, so the UI can use it as the single capability gate;
/// per-agent wording stays expressible here should one ever diverge.
pub fn fork_label(self) -> Option<&'static str> {
match self {
// Claude Code calls it branching.
CLIAgent::Claude => Some("Branch Session"),
CLIAgent::Codex | CLIAgent::Grok | CLIAgent::OpenCode => Some("Fork Session"),
CLIAgent::Claude | CLIAgent::Codex | CLIAgent::Grok | CLIAgent::OpenCode => {
Some("Fork Session")
}
_ => None,
}
}
+1 -1
View File
@@ -60,7 +60,7 @@ it never wraps or replaces the agent.
- **Notifications** — "needs your permission…" the moment an agent blocks on you, and "finished after Ns" per turn, honoring your notification policy
- **Branch at a glance** — each sidebar row shows its pane's git branch and working-tree diff (`+N M`), refreshed on `cd` and when a command finishes
- **Session resume** — panes lost to a reboot re-launch their agent conversation on restore, carrying the original launch flags (`claude --dangerously-skip-permissions --resume …`) (`restore_agent_sessions`, on by default)
- **Fork session** — branch a live agent conversation into a second, independent one by shelling the agent's own fork command (`codex fork <id>`, `claude --resume <id> --fork-session`, also OpenCode and Grok Build); the original is untouched and both continue separately. Right-click a pane to pick a split placement, or right-click the tab / sidebar row to open the fork in a new tab. The row is labelled with the agent's own word for it, so a Claude Code pane says *Branch Session*. Needs the agent's hooks installed, since the fork targets the session id they report; a remote pane can't fork, because the command would run against the local agent — and note a fork copies the whole transcript, so repeated forking costs real disk in the agent's own session store
- **Fork session** — branch a live agent conversation into a second, independent one by shelling the agent's own fork command (`codex fork <id>`, `claude --resume <id> --fork-session`, also OpenCode and Grok Build); the original is untouched and both continue separately. Right-click a pane to pick a split placement, or right-click the tab / sidebar row to open the fork in a new tab. Needs the agent's hooks installed, since the fork targets the session id they report; a remote pane can't fork, because the command would run against the local agent — and note a fork copies the whole transcript, so repeated forking costs real disk in the agent's own session store
- **Copy Session ID** — put the agent's native session id on the clipboard, beside *Copy Working Directory*, for pasting into `codex resume`, a bug report, or another tool
- **Context feed** — palette commands send the current selection or the repo's `git diff` to the running agent as a ready-made prompt
- **Tray icon** — a system tray / menu bar item that flips to an attention state the moment any agent needs your input; its menu lists every agent pane (brand avatar + status dot, click to reveal), switches the notification policy, and offers *Quit and Stop Daemon* alongside the plain session-keeping quit (`show_tray_icon`, on by default)
+1 -1
View File
@@ -57,7 +57,7 @@ Aider、Amp、OpenCode 等约 17 个)并在其外围加功能 —— 绝不包
- **通知** —— agent 卡在等你批准的那一刻弹 "needs your permission…",每轮结束弹 "finished after Ns",遵循你的通知策略
- **一眼看分支** —— 侧栏每行显示该 pane 的 git 分支和工作区改动(`+N M`),`cd` 或命令跑完时自动刷新
- **会话恢复** —— 重启后无法重连的 pane 会自动续上 agent 对话,并带上原始启动 flags(`claude --dangerously-skip-permissions --resume …``restore_agent_sessions`,默认开启)
- **Fork 会话** —— 直接调 agent 自己的 fork 命令(`codex fork <id>``claude --resume <id> --fork-session`OpenCode 和 Grok Build 同样支持),把当前对话分叉成一个独立会话;原会话原封不动,两边各自往下走。在 pane 上右键可选择分屏位置,在标签 / 侧栏行上右键则直接开新标签。菜单项用的是各 agent 自己的说法,所以 Claude Code 的 pane 里显示的是 *Branch Session*需要先装好该 agent 的 hooksfork 认的是 hooks 上报的 session id);远程 pane 不能 fork,因为命令会跑在本机的 agent 上;另外 fork 会整份复制对话历史,反复 fork 会在 agent 自己的会话目录里占掉不少磁盘
- **Fork 会话** —— 直接调 agent 自己的 fork 命令(`codex fork <id>``claude --resume <id> --fork-session`OpenCode 和 Grok Build 同样支持),把当前对话分叉成一个独立会话;原会话原封不动,两边各自往下走。在 pane 上右键可选择分屏位置,在标签 / 侧栏行上右键则直接开新标签。需要先装好该 agent 的 hooksfork 认的是 hooks 上报的 session id);远程 pane 不能 fork,因为命令会跑在本机的 agent 上;另外 fork 会整份复制对话历史,反复 fork 会在 agent 自己的会话目录里占掉不少磁盘
- **复制 Session ID** —— 把 agent 的原生 session id 复制到剪贴板,就在 *Copy Working Directory* 旁边,方便粘进 `codex resume`、bug 报告或别的工具
- **上下文回填** —— 面板命令把当前选区或仓库 `git diff` 打包成 prompt 直接喂给正在跑的 agent
- **托盘图标** —— 系统托盘 / 菜单栏常驻图标,任何 agent 等你输入时立即切换为提醒态;菜单列出所有 agent pane(品牌头像 + 状态点,点击直达)、可切换通知策略,并在保留会话的普通退出之外提供 *Quit and Stop Daemon*`show_tray_icon`,默认开启)
+1 -2
View File
@@ -6337,8 +6337,7 @@ impl Render for TerminalView {
// inherit it.
//
// Offered only for agents tty7 has a verified fork command
// for, labelled with that agent's own word for it ("Fork
// Session" / "Branch Session"). A *pane*-level ask is a spatial
// for. A *pane*-level ask is a spatial
// one, so this menu asks where the fork goes; the tab menu,
// which has no pane in hand, just opens a new tab (issue #211).
// Disabled — not hidden — until the session id is known, so the
+4 -4
View File
@@ -730,8 +730,8 @@ pub(crate) enum ForkPlacement {
/// menu-open time (like `tab_cwd`) so enablement can't go stale between render
/// and click.
pub(crate) struct TabAgentSession {
/// The agent's own word for forking, or `None` when tty7 has no verified
/// fork command for it — then no fork row is offered at all, rather than a
/// The fork row's label, or `None` when tty7 has no verified fork command
/// for this agent — then no fork row is offered at all, rather than a
/// disabled one promising a capability that doesn't exist.
pub(crate) fork_label: Option<&'static str>,
/// The agent's native session id, absent until its hooks report one.
@@ -3728,8 +3728,8 @@ impl Tty7App {
}
}
/// What the tab's agent-session menu rows ("Fork Session" / "Branch
/// Session" and "Copy Session ID") need, or `None` when the tab's
/// What the tab's agent-session menu rows ("Fork Session" and "Copy Session
/// ID") need, or `None` when the tab's
/// label-driving pane runs no coding agent — then neither row is offered.
/// Reads the same leaf `tab_cwd` does, so all three rows agree on which
/// pane a tab-level action means.
+7 -8
View File
@@ -1010,14 +1010,13 @@ impl Tty7App {
}));
}
// Fork / Branch Session — the same kind of operation as New Worktree
// Tab (spin a parallel line of work off this one), so it sits in the
// same block. A *tab*-level ask carries no placement question, so it
// lands in a new tab; the pane right-click menu is where the split
// directions live (issue #211). Offered only for agents tty7 has a
// verified fork command for, labelled with that agent's own word for
// it; disabled — not hidden — while the session id is still unknown,
// so the capability stays discoverable when the hooks aren't installed.
// Fork Session — the same kind of operation as New Worktree Tab (spin a
// parallel line of work off this one), so it sits in the same block. A
// *tab*-level ask carries no placement question, so it lands in a new
// tab; the pane right-click menu is where the split directions live
// (issue #211). Offered only for agents tty7 has a verified fork command
// for; disabled — not hidden — while the session id is still unknown, so
// the capability stays discoverable when the hooks aren't installed.
let agent_session = this.tab_agent_session(index, window, cx);
if let Some(session) = &agent_session
&& let Some(label) = session.fork_label