mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-21 08:02:21 +00:00
feat(agent): add TraeCode CLI support (#807)
* feat(agent): add TraeCode CLI support * fix(settings): index TraeCode agent hooks
This commit is contained in:
@@ -51,7 +51,7 @@ Native builds for macOS, Windows, and Linux on [**Releases**](https://github.com
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Agent-aware** | per-pane detection (19 CLIs) · status dot · notifications · branch + diff · tray icon when input is needed · resume after reboot · tab sidebar grouped by repository |
|
||||
| **Agent-aware** | per-pane detection (20 CLIs) · status dot · notifications · branch + diff · tray icon when input is needed · resume after reboot · tab sidebar grouped by repository |
|
||||
| **CLI + Skills** | bundled `tty7` CLI · [agent skill](skills/tty7/SKILL.md) · `run` streams a command and exits with its code · `split` · `send` · `wait --until free` · `capture` |
|
||||
| **Editor-grade input** | ghost suggestions from history · explained tab completion · syntax highlighting · multi-line editing · click places the caret · <kbd>⌃ R</kbd> fuzzy history |
|
||||
| **Window** | tabs & splits · <kbd>⌘ P</kbd> palette · <kbd>⌘ F</kbd> scrollback search · <kbd>⌘ J</kbd> panel with process tree and listening ports · 13 themes, your own YAML, iTerm2 import · IME |
|
||||
@@ -69,12 +69,13 @@ after a reboot. **Fork** needs both — the agent's own fork command, and the ho
|
||||
that tells tty7 which session to fork.
|
||||
|
||||
<details>
|
||||
<summary>The full support matrix, all nineteen</summary>
|
||||
<summary>The full support matrix, all twenty</summary>
|
||||
|
||||
| Agent | Detected | Status · resume | Fork |
|
||||
|---|:-:|:-:|:-:|
|
||||
| **Claude Code** | ✓ | ✓ | ✓ |
|
||||
| **Codex** | ✓ | ✓ | ✓ |
|
||||
| **TraeCode** | ✓ | ✓ | ✓ |
|
||||
| **Grok** | ✓ | ✓ | ✓ |
|
||||
| **OpenCode** | ✓ | ✓ | ✓ |
|
||||
| **Oh My Pi** | ✓ | ✓ | ✓ |
|
||||
|
||||
+3
-2
@@ -50,7 +50,7 @@ macOS、Windows、Linux 的原生构建都在 [**Releases**](https://github.com/
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Agent 感知** | 逐 pane 识别 19 个 CLI agent · 状态点 · 通知 · 分支 + diff · 需要输入时托盘图标提醒 · 重启后续上会话 · 侧边栏按仓库分组 |
|
||||
| **Agent 感知** | 逐 pane 识别 20 个 CLI agent · 状态点 · 通知 · 分支 + diff · 需要输入时托盘图标提醒 · 重启后续上会话 · 侧边栏按仓库分组 |
|
||||
| **CLI + Skills** | 安装包自带 `tty7` CLI · [agent skill](skills/tty7/SKILL.md) · `run` 转发命令输出并原样返回退出码 · `split` · `send` · `wait --until free` · `capture` |
|
||||
| **编辑器级输入** | 从历史推出影子建议 · Tab 补全附带说明 · 语法高亮 · 多行编辑 · 点击定位光标 · <kbd>⌃ R</kbd> 模糊搜索历史 |
|
||||
| **窗口** | 标签页与分屏 · <kbd>⌘ P</kbd> 命令面板 · <kbd>⌘ F</kbd> 回滚搜索 · <kbd>⌘ J</kbd> 侧栏列出进程树和监听端口 · 13 套主题,也能写自己的 YAML 或导入 iTerm2 配色 · 输入法 |
|
||||
@@ -66,12 +66,13 @@ macOS、Windows、Linux 的原生构建都在 [**Releases**](https://github.com/
|
||||
**Fork** 两个条件都要:agent 自己提供 fork 命令,且 hook 已装——tty7 得知道 fork 的是哪个会话。
|
||||
|
||||
<details>
|
||||
<summary>19 个 agent 的完整支持矩阵</summary>
|
||||
<summary>20 个 agent 的完整支持矩阵</summary>
|
||||
|
||||
| Agent | 识别 | 状态 · 重启恢复 | Fork |
|
||||
|---|:-:|:-:|:-:|
|
||||
| **Claude Code** | ✓ | ✓ | ✓ |
|
||||
| **Codex** | ✓ | ✓ | ✓ |
|
||||
| **TraeCode** | ✓ | ✓ | ✓ |
|
||||
| **Grok** | ✓ | ✓ | ✓ |
|
||||
| **OpenCode** | ✓ | ✓ | ✓ |
|
||||
| **Oh My Pi** | ✓ | ✓ | ✓ |
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<!-- TRAE brand mark, normalized from the user-provided trae-color.svg. -->
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M24 20.541H3.428v-3.426H0V3.4h24V20.54zM3.428 17.115h17.144V6.827H3.428v10.288zm8.573-5.196-2.425 2.424-2.424-2.424 2.424-2.424 2.425 2.424zm6.857-.001-2.424 2.423-2.425-2.423 2.425-2.425 2.424 2.425z" fill="#32F08C"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 409 B |
@@ -246,6 +246,7 @@ fn ancestor_pids(procs: &[crate::daemon::winproc::Proc]) -> Vec<u32> {
|
||||
pub enum HookAgent {
|
||||
Claude,
|
||||
Codex,
|
||||
TraeCode,
|
||||
Copilot,
|
||||
OpenCode,
|
||||
Pi,
|
||||
@@ -259,9 +260,10 @@ pub enum HookAgent {
|
||||
}
|
||||
|
||||
impl HookAgent {
|
||||
pub const ALL: [HookAgent; 12] = [
|
||||
pub const ALL: [HookAgent; 13] = [
|
||||
HookAgent::Claude,
|
||||
HookAgent::Codex,
|
||||
HookAgent::TraeCode,
|
||||
HookAgent::Copilot,
|
||||
HookAgent::OpenCode,
|
||||
HookAgent::Pi,
|
||||
@@ -283,6 +285,7 @@ impl HookAgent {
|
||||
match agent {
|
||||
CLIAgent::Claude => Some(HookAgent::Claude),
|
||||
CLIAgent::Codex => Some(HookAgent::Codex),
|
||||
CLIAgent::TraeCode => Some(HookAgent::TraeCode),
|
||||
CLIAgent::Copilot => Some(HookAgent::Copilot),
|
||||
CLIAgent::OpenCode => Some(HookAgent::OpenCode),
|
||||
CLIAgent::Pi => Some(HookAgent::Pi),
|
||||
@@ -310,6 +313,7 @@ impl HookAgent {
|
||||
match self {
|
||||
HookAgent::Claude => Some(CLAUDE_HOOK_EVENTS),
|
||||
HookAgent::Codex => Some(CODEX_HOOK_EVENTS),
|
||||
HookAgent::TraeCode => Some(TRAE_CODE_HOOK_EVENTS),
|
||||
HookAgent::Gemini => Some(GEMINI_HOOK_EVENTS),
|
||||
HookAgent::Droid => Some(DROID_HOOK_EVENTS),
|
||||
HookAgent::Qwen => Some(QWEN_HOOK_EVENTS),
|
||||
@@ -337,6 +341,7 @@ impl HookAgent {
|
||||
match self {
|
||||
HookAgent::Claude => "claude",
|
||||
HookAgent::Codex => "codex",
|
||||
HookAgent::TraeCode => "traecli",
|
||||
HookAgent::Copilot => "copilot",
|
||||
HookAgent::OpenCode => "opencode",
|
||||
HookAgent::Pi => "pi",
|
||||
@@ -354,6 +359,7 @@ impl HookAgent {
|
||||
match self {
|
||||
HookAgent::Claude => "Claude Code",
|
||||
HookAgent::Codex => "Codex",
|
||||
HookAgent::TraeCode => "TraeCode",
|
||||
HookAgent::Copilot => "Copilot CLI",
|
||||
HookAgent::OpenCode => "OpenCode",
|
||||
HookAgent::Pi => "Pi",
|
||||
@@ -375,6 +381,7 @@ impl HookAgent {
|
||||
match self {
|
||||
HookAgent::Claude => target.claude_settings_path(),
|
||||
HookAgent::Codex => target.under_home(&[".codex", "hooks.json"]),
|
||||
HookAgent::TraeCode => target.traecli_hooks_path(),
|
||||
HookAgent::Copilot => target.under_home(&[".copilot", "hooks", OWNED_FILE_STEM_JSON]),
|
||||
HookAgent::OpenCode => target.under(
|
||||
&target.xdg_config_dir(),
|
||||
@@ -487,6 +494,18 @@ impl<'a> HookTarget<'a> {
|
||||
self.under_home(&[".kimi-code", "config.toml"])
|
||||
}
|
||||
|
||||
fn traecli_hooks_path(&self) -> PathBuf {
|
||||
if self.is_local() {
|
||||
if let Some(dir) = std::env::var_os("TRAECLI_HOME").filter(|d| !d.is_empty()) {
|
||||
return PathBuf::from(dir).join("hooks.json");
|
||||
}
|
||||
if let Some(dir) = std::env::var_os("TRAE_HOME").filter(|d| !d.is_empty()) {
|
||||
return PathBuf::from(dir).join("cli").join("hooks.json");
|
||||
}
|
||||
}
|
||||
self.under_home(&[".trae", "cli", "hooks.json"])
|
||||
}
|
||||
|
||||
fn hook_command(&self, agent: HookAgent, event: &str) -> String {
|
||||
if let Some(exe) = self.hook_command_exe() {
|
||||
return format!("{exe} agent-hook {} {event}", agent.slug());
|
||||
@@ -697,6 +716,15 @@ const CODEX_HOOK_EVENTS: &[(&str, &str)] = &[
|
||||
("Stop", "stop"),
|
||||
];
|
||||
|
||||
const TRAE_CODE_HOOK_EVENTS: &[(&str, &str)] = &[
|
||||
("SessionStart", "session-start"),
|
||||
("UserPromptSubmit", "prompt-submit"),
|
||||
("PermissionRequest", "permission-request"),
|
||||
("PostToolUse", "tool-complete"),
|
||||
("Stop", "stop"),
|
||||
("SessionEnd", "session-end"),
|
||||
];
|
||||
|
||||
/// Gemini names the turn boundaries after the agent rather than the user, and
|
||||
/// omitting `matcher` matches everything (`hookPlanner.ts`, `!entry.matcher`),
|
||||
/// so the bare entries [`hook_map_install`] already writes are enough.
|
||||
@@ -1106,6 +1134,7 @@ fn owned_file_content(target: &HookTarget, agent: HookAgent) -> Option<String> {
|
||||
HookAgent::Goose => goose_hooks_json(target),
|
||||
HookAgent::Claude
|
||||
| HookAgent::Codex
|
||||
| HookAgent::TraeCode
|
||||
| HookAgent::Gemini
|
||||
| HookAgent::Droid
|
||||
| HookAgent::Qwen
|
||||
@@ -1538,6 +1567,7 @@ mod tests {
|
||||
let mut events: Vec<&str> = CLAUDE_HOOK_EVENTS
|
||||
.iter()
|
||||
.chain(CODEX_HOOK_EVENTS)
|
||||
.chain(TRAE_CODE_HOOK_EVENTS)
|
||||
.chain(GEMINI_HOOK_EVENTS)
|
||||
.chain(DROID_HOOK_EVENTS)
|
||||
.chain(QWEN_HOOK_EVENTS)
|
||||
@@ -1571,6 +1601,7 @@ mod tests {
|
||||
(HookAgent::Gemini, "/home/me/.gemini/settings.json"),
|
||||
(HookAgent::Droid, "/home/me/.factory/settings.json"),
|
||||
(HookAgent::Qwen, "/home/me/.qwen/settings.json"),
|
||||
(HookAgent::TraeCode, "/home/me/.trae/cli/hooks.json"),
|
||||
(
|
||||
HookAgent::Goose,
|
||||
"/home/me/.agents/plugins/tty7/hooks/hooks.json",
|
||||
@@ -1862,6 +1893,7 @@ mod tests {
|
||||
for (agent, expected) in [
|
||||
(HookAgent::Claude, "/home/me/.claude/settings.json"),
|
||||
(HookAgent::Codex, "/home/me/.codex/hooks.json"),
|
||||
(HookAgent::TraeCode, "/home/me/.trae/cli/hooks.json"),
|
||||
(HookAgent::Copilot, "/home/me/.copilot/hooks/tty7.json"),
|
||||
(
|
||||
HookAgent::OpenCode,
|
||||
|
||||
@@ -23,12 +23,16 @@ pub enum CLIAgent {
|
||||
Qwen,
|
||||
OhMyPi,
|
||||
Kimi,
|
||||
// Keep new variants at the end: daemon messages serialize this enum and
|
||||
// moving an existing discriminant would break mixed-version clients.
|
||||
TraeCode,
|
||||
}
|
||||
|
||||
impl CLIAgent {
|
||||
pub const ALL: [CLIAgent; 19] = [
|
||||
pub const ALL: [CLIAgent; 20] = [
|
||||
CLIAgent::Claude,
|
||||
CLIAgent::Codex,
|
||||
CLIAgent::TraeCode,
|
||||
CLIAgent::Gemini,
|
||||
CLIAgent::Aider,
|
||||
CLIAgent::Amp,
|
||||
@@ -52,6 +56,7 @@ impl CLIAgent {
|
||||
match self {
|
||||
CLIAgent::Claude => &["claude", "claude-code"],
|
||||
CLIAgent::Codex => &["codex", "codex-cli"],
|
||||
CLIAgent::TraeCode => &["traecli", "traex"],
|
||||
CLIAgent::Gemini => &["gemini", "gemini-cli"],
|
||||
CLIAgent::Aider => &["aider", "aider-chat"],
|
||||
CLIAgent::Amp => &["amp"],
|
||||
@@ -85,6 +90,7 @@ impl CLIAgent {
|
||||
match self {
|
||||
CLIAgent::Claude => "claude",
|
||||
CLIAgent::Codex => "codex",
|
||||
CLIAgent::TraeCode => "traecli",
|
||||
CLIAgent::Gemini => "gemini",
|
||||
CLIAgent::Aider => "aider",
|
||||
CLIAgent::Amp => "amp",
|
||||
@@ -114,6 +120,7 @@ impl CLIAgent {
|
||||
match self {
|
||||
CLIAgent::Claude => "Claude Code",
|
||||
CLIAgent::Codex => "Codex",
|
||||
CLIAgent::TraeCode => "TraeCode",
|
||||
CLIAgent::Gemini => "Gemini",
|
||||
CLIAgent::Aider => "Aider",
|
||||
CLIAgent::Amp => "Amp",
|
||||
@@ -146,6 +153,7 @@ impl CLIAgent {
|
||||
match self {
|
||||
CLIAgent::Claude => Some(format!("claude{flags} --resume {session_id}")),
|
||||
CLIAgent::Codex => Some(format!("codex resume {session_id}{flags}")),
|
||||
CLIAgent::TraeCode => Some(format!("traecli resume {session_id}{flags}")),
|
||||
CLIAgent::Gemini => Some(format!("gemini{flags} --resume {session_id}")),
|
||||
CLIAgent::OpenCode => Some(format!("opencode{flags} --session {session_id}")),
|
||||
CLIAgent::Amp => Some(format!("amp threads continue {session_id}{flags}")),
|
||||
@@ -189,6 +197,7 @@ impl CLIAgent {
|
||||
let flags = self.session_command_flags(session_id, launch_argv)?;
|
||||
match self {
|
||||
CLIAgent::Codex => Some(format!("codex fork {session_id}{flags}")),
|
||||
CLIAgent::TraeCode => Some(format!("traecli fork {session_id}{flags}")),
|
||||
CLIAgent::Claude => Some(format!(
|
||||
"claude{flags} --resume {session_id} --fork-session"
|
||||
)),
|
||||
@@ -213,6 +222,7 @@ impl CLIAgent {
|
||||
match self {
|
||||
CLIAgent::Claude
|
||||
| CLIAgent::Codex
|
||||
| CLIAgent::TraeCode
|
||||
| CLIAgent::Grok
|
||||
| CLIAgent::OpenCode
|
||||
| CLIAgent::OhMyPi
|
||||
@@ -260,7 +270,9 @@ impl CLIAgent {
|
||||
let named = argv.iter().position(|t| names_self(t))?;
|
||||
let mut tail: Vec<&str> = argv[named + 1..].iter().map(String::as_str).collect();
|
||||
|
||||
if self == CLIAgent::Codex && matches!(tail.first(), Some(&"resume") | Some(&"fork")) {
|
||||
if matches!(self, CLIAgent::Codex | CLIAgent::TraeCode)
|
||||
&& matches!(tail.first(), Some(&"resume") | Some(&"fork"))
|
||||
{
|
||||
tail.remove(0);
|
||||
if tail.first().is_some_and(|t| !t.starts_with('-')) {
|
||||
tail.remove(0);
|
||||
@@ -339,6 +351,7 @@ impl CLIAgent {
|
||||
CLIAgent::Antigravity => &["--conversation", "--continue", "-c"],
|
||||
CLIAgent::OpenCode => &["--session", "-s", "--continue", "-c", "--fork"],
|
||||
CLIAgent::Codex => &["--last"],
|
||||
CLIAgent::TraeCode => &["--last", "--resume", "--session-id"],
|
||||
CLIAgent::Pi => &[
|
||||
"--session",
|
||||
"--session-id",
|
||||
@@ -422,6 +435,9 @@ impl CLIAgent {
|
||||
match self {
|
||||
CLIAgent::Claude => 0xD97757,
|
||||
CLIAgent::Codex => 0x000000,
|
||||
// The brand mark carries its own green foreground on a black
|
||||
// field, so the surrounding tab avatar needs to stay black too.
|
||||
CLIAgent::TraeCode => 0x000000,
|
||||
CLIAgent::Gemini => 0x4285F4,
|
||||
CLIAgent::Aider => 0x14B014,
|
||||
CLIAgent::Amp => 0xF34E3F,
|
||||
@@ -448,6 +464,7 @@ impl CLIAgent {
|
||||
match self {
|
||||
CLIAgent::Claude => "icons/agents/claude.svg",
|
||||
CLIAgent::Codex => "icons/agents/codex.svg",
|
||||
CLIAgent::TraeCode => "icons/agents/traecli.svg",
|
||||
CLIAgent::Gemini => "icons/agents/gemini.svg",
|
||||
CLIAgent::Amp => "icons/agents/amp.svg",
|
||||
CLIAgent::OpenCode => "icons/agents/opencode.svg",
|
||||
@@ -771,6 +788,14 @@ mod tests {
|
||||
CLIAgent::detect_from_argv(&argv(&["/opt/homebrew/bin/codex", "--model", "o3"])),
|
||||
Some(CLIAgent::Codex)
|
||||
);
|
||||
assert_eq!(
|
||||
CLIAgent::detect_from_argv(&argv(&["/Users/me/.local/bin/traecli"])),
|
||||
Some(CLIAgent::TraeCode)
|
||||
);
|
||||
assert_eq!(
|
||||
CLIAgent::detect_from_argv(&argv(&["traex"])),
|
||||
Some(CLIAgent::TraeCode)
|
||||
);
|
||||
assert_eq!(
|
||||
CLIAgent::detect_from_argv(&argv(&["/usr/local/bin/gemini"])),
|
||||
Some(CLIAgent::Gemini)
|
||||
@@ -1192,6 +1217,12 @@ mod tests {
|
||||
CLIAgent::Codex.resume_command("th_read.9", None).as_deref(),
|
||||
Some("codex resume th_read.9")
|
||||
);
|
||||
assert_eq!(
|
||||
CLIAgent::TraeCode
|
||||
.resume_command("019c-123", None)
|
||||
.as_deref(),
|
||||
Some("traecli resume 019c-123")
|
||||
);
|
||||
assert_eq!(
|
||||
CLIAgent::Pi
|
||||
.resume_command("0199c3f2-1b0e-7c3a-9f21-6d4b8e2a5c17", None)
|
||||
@@ -1522,6 +1553,10 @@ mod tests {
|
||||
CLIAgent::Codex.fork_command("abc-123", None).as_deref(),
|
||||
Some("codex fork abc-123")
|
||||
);
|
||||
assert_eq!(
|
||||
CLIAgent::TraeCode.fork_command("019c-123", None).as_deref(),
|
||||
Some("traecli fork 019c-123")
|
||||
);
|
||||
assert_eq!(
|
||||
CLIAgent::Claude.fork_command("abc-123", None).as_deref(),
|
||||
Some("claude --resume abc-123 --fork-session")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: "Coding agents"
|
||||
description: "What tty7 does around Claude Code, Codex, and 17 others — without ever wrapping them."
|
||||
description: "What tty7 does around Claude Code, Codex, TraeCode, and 17 others — without ever wrapping them."
|
||||
---
|
||||
|
||||
tty7 recognises coding agents running in a pane and builds around them. It does
|
||||
@@ -15,12 +15,13 @@ need, and what changed.
|
||||
|
||||
## Which agents
|
||||
|
||||
Nineteen CLIs are recognised on sight, by the command running in the pane:
|
||||
Twenty CLIs are recognised on sight, by the command running in the pane:
|
||||
|
||||
| Agent | Command |
|
||||
|---|---|
|
||||
| Claude Code | `claude`, `claude-code` |
|
||||
| Codex | `codex`, `codex-cli` |
|
||||
| TraeCode | `traecli`, `traex` |
|
||||
| Gemini | `gemini`, `gemini-cli` |
|
||||
| Copilot | `copilot` |
|
||||
| Cursor | `cursor-agent` |
|
||||
@@ -58,7 +59,7 @@ If you launch agents through a wrapper script, map its name to an agent in
|
||||
```
|
||||
|
||||
The key is your command's name; the value is one of the slugs above (`claude`,
|
||||
`codex`, `gemini`, `aider`, `amp`, `opencode`, `copilot`, `cursor`, `goose`,
|
||||
`codex`, `traecli`, `gemini`, `aider`, `amp`, `opencode`, `copilot`, `cursor`, `goose`,
|
||||
`droid`, `pi`, `auggie`, `hermes`, `vibe`, `antigravity`, `grok`, `qwen`,
|
||||
`omp`, `kimi`).
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ or right-click the **tab or sidebar row** to open the fork in a new tab.
|
||||
|---|---|
|
||||
| Claude Code | `claude --resume <id> --fork-session` |
|
||||
| Codex | `codex fork <id>` |
|
||||
| TraeCode | `traecli fork <id>` |
|
||||
| Grok | `grok --resume <id> --fork-session` |
|
||||
| OpenCode | `opencode --session <id> --fork` |
|
||||
| Oh My Pi | `omp --fork <id>` |
|
||||
|
||||
@@ -14,7 +14,7 @@ the agent say which one it is.
|
||||
|
||||
| Agent | |
|
||||
|---|---|
|
||||
| Claude Code · Codex · Copilot CLI · OpenCode · Pi · Grok Build · Oh My Pi · Gemini · Droid · Qwen Code · Goose · Kimi Code | Hooks available |
|
||||
| Claude Code · Codex · TraeCode · Copilot CLI · OpenCode · Pi · Grok Build · Oh My Pi · Gemini · Droid · Qwen Code · Goose · Kimi Code | Hooks available |
|
||||
| Aider · Amp · Cursor · Auggie · Hermes · Vibe · Antigravity | Detected and labelled, but no status channel yet |
|
||||
|
||||
Installing writes into that agent's own configuration directory. Once installed
|
||||
|
||||
@@ -54,13 +54,13 @@ leave it off if you type accented characters.
|
||||
|
||||
## 4. If you use coding agents, install the hooks
|
||||
|
||||
**Settings → Agents.** tty7 detects 19 coding CLIs by process name on its own —
|
||||
**Settings → Agents.** tty7 detects 20 coding CLIs by process name on its own —
|
||||
you get brand avatars and tab labels for free. The *status dots*, the "needs
|
||||
your permission" notifications, and `tty7 wait` all need one more thing: a small
|
||||
hook the agent calls to report what it is doing.
|
||||
|
||||
Click **Install** next to Claude Code, Codex, Copilot CLI, OpenCode, Pi, Grok
|
||||
Build, or Oh My Pi. It writes into that agent's own config directory and can be
|
||||
Click **Install** next to Claude Code, Codex, TraeCode, Copilot CLI, OpenCode,
|
||||
Pi, Grok Build, or Oh My Pi. It writes into that agent's own config directory and can be
|
||||
removed from the same row.
|
||||
|
||||
[More about agents →](/agents/status)
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ something floods the screen.
|
||||
syntax highlighting, click-to-place-caret, real multi-line editing.
|
||||
</Card>
|
||||
<Card title="Agent-aware" icon="robot" href="/agents/overview">
|
||||
19 coding CLIs are recognised on sight. Per-pane status dots, notifications
|
||||
20 coding CLIs are recognised on sight. Per-pane status dots, notifications
|
||||
when one needs you, git context, and session resume after a reboot.
|
||||
</Card>
|
||||
<Card title="Remote work that feels local" icon="server" href="/remote/workspaces">
|
||||
|
||||
@@ -49,6 +49,7 @@ fn agent_icon(path: &str) -> Option<&'static [u8]> {
|
||||
"icons/refresh.svg" => include_bytes!("../../assets/icons/refresh.svg"),
|
||||
"icons/agents/claude.svg" => include_bytes!("../../assets/icons/agents/claude.svg"),
|
||||
"icons/agents/codex.svg" => include_bytes!("../../assets/icons/agents/codex.svg"),
|
||||
"icons/agents/traecli.svg" => include_bytes!("../../assets/icons/agents/traecli.svg"),
|
||||
"icons/agents/gemini.svg" => include_bytes!("../../assets/icons/agents/gemini.svg"),
|
||||
"icons/agents/amp.svg" => include_bytes!("../../assets/icons/agents/amp.svg"),
|
||||
"icons/agents/opencode.svg" => include_bytes!("../../assets/icons/agents/opencode.svg"),
|
||||
|
||||
@@ -738,6 +738,7 @@ pub fn translate_en(key: L10nKey) -> &'static str {
|
||||
}
|
||||
L10nKey::SettingsAgentClaudeCode => "Claude Code",
|
||||
L10nKey::SettingsAgentCodex => "Codex",
|
||||
L10nKey::SettingsAgentTraeCode => "TraeCode",
|
||||
L10nKey::SettingsAgentCopilotCli => "Copilot CLI",
|
||||
L10nKey::SettingsAgentOpencode => "OpenCode",
|
||||
L10nKey::SettingsAgentPi => "Pi",
|
||||
@@ -768,6 +769,9 @@ pub fn translate_en(key: L10nKey) -> &'static str {
|
||||
"agent integration hooks install uninstall status rich session working waiting tab bar sidebar badge claude"
|
||||
}
|
||||
L10nKey::SettingsSearchCodexKeywords => "agent integration hooks install openai codex",
|
||||
L10nKey::SettingsSearchTraeCodeKeywords => {
|
||||
"agent integration hooks install trae code traecli traex"
|
||||
}
|
||||
L10nKey::SettingsSearchCommandLineToolKeywords => {
|
||||
"command line tool cli tty7 path shell command install symlink terminal iterm agent script"
|
||||
}
|
||||
|
||||
@@ -747,6 +747,7 @@ pub fn translate_ja(key: L10nKey) -> Option<&'static str> {
|
||||
}
|
||||
L10nKey::SettingsAgentClaudeCode => "Claude Code",
|
||||
L10nKey::SettingsAgentCodex => "Codex",
|
||||
L10nKey::SettingsAgentTraeCode => "TraeCode",
|
||||
L10nKey::SettingsAgentCopilotCli => "Copilot CLI",
|
||||
L10nKey::SettingsAgentOpencode => "OpenCode",
|
||||
L10nKey::SettingsAgentPi => "Pi",
|
||||
@@ -787,6 +788,9 @@ pub fn translate_ja(key: L10nKey) -> Option<&'static str> {
|
||||
L10nKey::SettingsSearchCodexKeywords => {
|
||||
"エージェント 統合 フック インストール openai codex agent integration hooks install"
|
||||
}
|
||||
L10nKey::SettingsSearchTraeCodeKeywords => {
|
||||
"エージェント 統合 フック インストール trae code traecli traex agent integration hooks install"
|
||||
}
|
||||
L10nKey::SettingsSearchCommandLineToolKeywords => {
|
||||
"cli tty7 パス シェル コマンド インストール シンボリックリンク ターミナル iterm エージェント スクリプト command line tool"
|
||||
}
|
||||
|
||||
@@ -570,6 +570,7 @@ l10n_keys! {
|
||||
SettingsAppHttpProxyInvalid,
|
||||
SettingsAgentClaudeCode,
|
||||
SettingsAgentCodex,
|
||||
SettingsAgentTraeCode,
|
||||
SettingsAgentCopilotCli,
|
||||
SettingsAgentOpencode,
|
||||
SettingsAgentPi,
|
||||
@@ -593,6 +594,7 @@ l10n_keys! {
|
||||
SettingsSearchBoldFontKeywords,
|
||||
SettingsSearchClaudeCodeKeywords,
|
||||
SettingsSearchCodexKeywords,
|
||||
SettingsSearchTraeCodeKeywords,
|
||||
SettingsSearchCommandLineToolKeywords,
|
||||
SettingsSearchCommandLineToolTitle,
|
||||
SettingsSearchCopilotCliKeywords,
|
||||
@@ -1532,6 +1534,7 @@ mod tests {
|
||||
// Product names.
|
||||
L10nKey::SettingsAgentClaudeCode,
|
||||
L10nKey::SettingsAgentCodex,
|
||||
L10nKey::SettingsAgentTraeCode,
|
||||
L10nKey::SettingsAgentCopilotCli,
|
||||
L10nKey::SettingsAgentDroid,
|
||||
L10nKey::SettingsAgentGemini,
|
||||
|
||||
@@ -656,6 +656,7 @@ pub fn translate_zh(key: L10nKey) -> Option<&'static str> {
|
||||
L10nKey::SettingsAppHttpProxyInvalid => "不是有效的代理地址,该值未保存。",
|
||||
L10nKey::SettingsAgentClaudeCode => "Claude Code",
|
||||
L10nKey::SettingsAgentCodex => "Codex",
|
||||
L10nKey::SettingsAgentTraeCode => "TraeCode",
|
||||
L10nKey::SettingsAgentCopilotCli => "Copilot CLI",
|
||||
L10nKey::SettingsAgentOpencode => "OpenCode",
|
||||
L10nKey::SettingsAgentPi => "Pi",
|
||||
@@ -694,6 +695,9 @@ pub fn translate_zh(key: L10nKey) -> Option<&'static str> {
|
||||
L10nKey::SettingsSearchCodexKeywords => {
|
||||
"Codex agent 集成 hook 安装 OpenAI codex agent integration hooks install"
|
||||
}
|
||||
L10nKey::SettingsSearchTraeCodeKeywords => {
|
||||
"TraeCode traecli traex agent 集成 hook 安装 agent integration hooks install"
|
||||
}
|
||||
L10nKey::SettingsSearchCommandLineToolKeywords => {
|
||||
"命令行工具 cli tty7 路径 shell 命令 安装 符号链接 terminal command line tool"
|
||||
}
|
||||
|
||||
@@ -601,6 +601,11 @@ fn settings_search_entries() -> &'static [SearchEntry] {
|
||||
title: SettingsAgentCodex,
|
||||
keywords: SettingsSearchCodexKeywords,
|
||||
},
|
||||
SearchEntry {
|
||||
section: Agents,
|
||||
title: SettingsAgentTraeCode,
|
||||
keywords: SettingsSearchTraeCodeKeywords,
|
||||
},
|
||||
SearchEntry {
|
||||
section: Agents,
|
||||
title: SettingsAgentCopilotCli,
|
||||
|
||||
+8
-1
@@ -1301,7 +1301,14 @@ impl Tty7App {
|
||||
gpui::svg()
|
||||
.path(agent.icon_path())
|
||||
.size(px(size * 0.54))
|
||||
.text_color(gpui::white()),
|
||||
// SVG assets are rendered as a single-colour mask.
|
||||
// TraeCode's black field comes from the avatar, and
|
||||
// its brand mark uses the official green.
|
||||
.text_color(if agent == crate::core::cli_agent::CLIAgent::TraeCode {
|
||||
gpui::rgb(0x32F08C)
|
||||
} else {
|
||||
gpui::rgb(0xFFFFFF)
|
||||
}),
|
||||
)
|
||||
.when_some(dot, |b, dot| b.child(dot))
|
||||
.tooltip(move |window, cx| {
|
||||
|
||||
Reference in New Issue
Block a user