parent
2fcf9b678d
commit
1d56cd0e18
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
### Added
|
||||
- Added `ui.right_click_passthrough_modifier` so a configured modifier such as `ctrl` can forward right-click hold and drag gestures to mouse-reporting pane apps while normal right-click still opens Herdr's pane menu. (#148)
|
||||
- Added Kilo Code CLI automatic detection for idle, working, and blocked terminal states. (#270)
|
||||
|
||||
## [0.6.6] - 2026-05-31
|
||||
|
||||
|
|
|
|||
|
|
@ -154,6 +154,7 @@ automatic detection works out of the box. process name matching plus terminal ou
|
|||
| [opencode](https://github.com/anomalyco/opencode) | ✓ | ✓ | ✓ |
|
||||
| [grok cli](https://x.ai/grok) | ✓ | ✓ | ✓ |
|
||||
| [hermes agent](https://github.com/NousResearch/hermes-agent) | ✓ | ✓ | ✓ |
|
||||
| [kilo code cli](https://kilo.ai/) | ✓ | ✓ | ✓ |
|
||||
| cursor agent | ✓ | ✓ | ✓ |
|
||||
| antigravity cli | ✓ | ✓ | ✓ |
|
||||
| kimi code cli | ✓ | ✓ | ✓ |
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ Automatic detection works out of the box for common coding agents.
|
|||
| OpenCode | yes | yes | yes |
|
||||
| Grok CLI | yes | yes | yes |
|
||||
| Hermes Agent | yes | yes | yes |
|
||||
| Kilo Code CLI | yes | yes | yes |
|
||||
| Cursor Agent | yes | yes | yes |
|
||||
| Antigravity CLI | yes | yes | yes |
|
||||
| Kimi Code CLI | yes | yes | yes |
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ cjk_ime_cursor_shape = "steady_block"
|
|||
|
||||
When enabled, the cursor stays visible at the focused pane's reported position. If the pane reports no cursor position, the anchor falls back to the pane's top-left so a stable IME hint is always available.
|
||||
|
||||
`cjk_ime_agents` is an optional allow-list. When empty, the reveal applies to any focused pane. When non-empty, the reveal only applies if the focused pane's detected agent matches one of the listed names — useful to enable the reveal only for AI-agent TUIs that paint their own cursor while leaving plain shells untouched. Accepted names: `pi`, `claude`, `codex`, `gemini`, `cursor`, `agy`, `cline`, `opencode`, `copilot`, `kimi`, `kiro`, `droid`, `amp`, `grok`, `hermes`, `qodercli`, and `qoder`. Unknown names are ignored; if the list contains no valid names, the reveal does not apply.
|
||||
`cjk_ime_agents` is an optional allow-list. When empty, the reveal applies to any focused pane. When non-empty, the reveal only applies if the focused pane's detected agent matches one of the listed names — useful to enable the reveal only for AI-agent TUIs that paint their own cursor while leaving plain shells untouched. Accepted names: `pi`, `claude`, `codex`, `gemini`, `cursor`, `agy`, `cline`, `opencode`, `copilot`, `kimi`, `kiro`, `droid`, `amp`, `grok`, `hermes`, `kilo`, `qodercli`, and `qoder`. Unknown names are ignored; if the list contains no valid names, the reveal does not apply.
|
||||
|
||||
`cjk_ime_cursor_shape` controls the DECSCUSR shape rendered for the IME anchor. Accepted values: `block`, `steady_block` (default), `underline`, `steady_underline`, `bar`, `steady_bar`.
|
||||
|
||||
|
|
|
|||
|
|
@ -414,7 +414,8 @@ pub struct ExperimentalConfig {
|
|||
/// list means apply to any focused pane. Unknown agent names are ignored;
|
||||
/// if the list contains no valid names, the reveal does not apply.
|
||||
/// Accepted names: pi, claude, codex, gemini, cursor, cline, opencode,
|
||||
/// copilot, kimi, kiro, droid, amp, grok, hermes. Default: empty.
|
||||
/// copilot, kimi, kiro, droid, amp, grok, hermes, kilo, qodercli, qoder.
|
||||
/// Default: empty.
|
||||
pub cjk_ime_agents: Vec<String>,
|
||||
/// Cursor shape rendered for the IME anchor when
|
||||
/// `reveal_hidden_cursor_for_cjk_ime` is enabled. Default: "steady_block".
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ pub struct AgentSoundOverrides {
|
|||
pub amp: AgentSoundSetting,
|
||||
pub grok: AgentSoundSetting,
|
||||
pub hermes: AgentSoundSetting,
|
||||
pub kilo: AgentSoundSetting,
|
||||
pub qodercli: AgentSoundSetting,
|
||||
}
|
||||
|
||||
|
|
@ -131,6 +132,7 @@ impl AgentSoundOverrides {
|
|||
Some(Agent::Amp) => self.amp,
|
||||
Some(Agent::Grok) => self.grok,
|
||||
Some(Agent::Hermes) => self.hermes,
|
||||
Some(Agent::Kilo) => self.kilo,
|
||||
Some(Agent::Qodercli) => self.qodercli,
|
||||
None => AgentSoundSetting::Default,
|
||||
}
|
||||
|
|
@ -167,6 +169,7 @@ impl Default for AgentSoundOverrides {
|
|||
amp: AgentSoundSetting::Default,
|
||||
grok: AgentSoundSetting::Default,
|
||||
hermes: AgentSoundSetting::Default,
|
||||
kilo: AgentSoundSetting::Default,
|
||||
qodercli: AgentSoundSetting::Default,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
use super::super::AgentState;
|
||||
|
||||
pub(super) fn detect(content: &str) -> AgentState {
|
||||
if content.to_lowercase().contains("esc interrupt") {
|
||||
return AgentState::Working;
|
||||
}
|
||||
|
||||
super::opencode::detect(content)
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ pub(super) mod gemini;
|
|||
pub(super) mod github_copilot;
|
||||
pub(super) mod grok;
|
||||
pub(super) mod hermes;
|
||||
pub(super) mod kilo;
|
||||
pub(super) mod kimi;
|
||||
pub(super) mod kiro;
|
||||
pub(super) mod opencode;
|
||||
|
|
@ -34,6 +35,7 @@ pub(super) fn detect(agent: Agent, screen_content: &str) -> AgentDetection {
|
|||
Agent::Amp => amp::detect(screen_content),
|
||||
Agent::Grok => grok::detect(screen_content),
|
||||
Agent::Hermes => hermes::detect(screen_content),
|
||||
Agent::Kilo => kilo::detect(screen_content),
|
||||
Agent::Qodercli => qodercli::detect(screen_content),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ pub enum Agent {
|
|||
Amp,
|
||||
Grok,
|
||||
Hermes,
|
||||
Kilo,
|
||||
Qodercli,
|
||||
}
|
||||
|
||||
|
|
@ -74,6 +75,7 @@ pub fn agent_label(agent: Agent) -> &'static str {
|
|||
Agent::Amp => "amp",
|
||||
Agent::Grok => "grok",
|
||||
Agent::Hermes => "hermes",
|
||||
Agent::Kilo => "kilo",
|
||||
Agent::Qodercli => "qodercli",
|
||||
}
|
||||
}
|
||||
|
|
@ -96,6 +98,7 @@ pub fn parse_agent_label(agent: &str) -> Option<Agent> {
|
|||
"amp" | "amp-local" => Some(Agent::Amp),
|
||||
"grok" | "grok-build" => Some(Agent::Grok),
|
||||
"hermes" | "hermes-agent" => Some(Agent::Hermes),
|
||||
"kilo" | "kilo-code" | "kilo code" => Some(Agent::Kilo),
|
||||
"qodercli" | "qoderclicn" | "qoder" | "qodercn" => Some(Agent::Qodercli),
|
||||
_ => None,
|
||||
}
|
||||
|
|
@ -122,6 +125,7 @@ pub fn identify_agent(process_name: &str) -> Option<Agent> {
|
|||
"amp" | "amp-local" => Some(Agent::Amp),
|
||||
"grok" | "grok-build" => Some(Agent::Grok),
|
||||
"hermes" | "hermes-agent" => Some(Agent::Hermes),
|
||||
"kilo" | "kilo-code" | "kilo code" => Some(Agent::Kilo),
|
||||
"qodercli" | "qoderclicn" | "qoder" | "qodercn" => Some(Agent::Qodercli),
|
||||
_ => None,
|
||||
}
|
||||
|
|
@ -255,6 +259,11 @@ fn detect_qodercli(content: &str) -> AgentState {
|
|||
detect_state(Some(Agent::Qodercli), content)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn detect_kilo(content: &str) -> AgentState {
|
||||
detect_state(Some(Agent::Kilo), content)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Shared helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -567,6 +576,11 @@ mod tests {
|
|||
AgentState::Working,
|
||||
),
|
||||
(Agent::Hermes, "msg=interrupt", AgentState::Working),
|
||||
(
|
||||
Agent::Kilo,
|
||||
"Ask · DeepSeek V4 Pro\nesc interrupt",
|
||||
AgentState::Working,
|
||||
),
|
||||
(Agent::Qodercli, "\u{280B} Thinking...", AgentState::Working),
|
||||
];
|
||||
|
||||
|
|
@ -604,6 +618,8 @@ mod tests {
|
|||
assert_eq!(identify_agent("grok-build"), Some(Agent::Grok));
|
||||
assert_eq!(identify_agent("hermes"), Some(Agent::Hermes));
|
||||
assert_eq!(identify_agent("hermes-agent"), Some(Agent::Hermes));
|
||||
assert_eq!(identify_agent("kilo"), Some(Agent::Kilo));
|
||||
assert_eq!(identify_agent("kilo-code"), Some(Agent::Kilo));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -623,6 +639,7 @@ mod tests {
|
|||
assert_eq!(parse_agent_label("kiro-cli"), Some(Agent::Kiro));
|
||||
assert_eq!(parse_agent_label("grok-build"), Some(Agent::Grok));
|
||||
assert_eq!(parse_agent_label("hermes-agent"), Some(Agent::Hermes));
|
||||
assert_eq!(parse_agent_label("kilo-code"), Some(Agent::Kilo));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -634,6 +651,7 @@ mod tests {
|
|||
assert_eq!(agent_label(Agent::Kiro), "kiro");
|
||||
assert_eq!(agent_label(Agent::Grok), "grok");
|
||||
assert_eq!(agent_label(Agent::Hermes), "hermes");
|
||||
assert_eq!(agent_label(Agent::Kilo), "kilo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1581,6 +1599,38 @@ mod tests {
|
|||
assert_eq!(detect_opencode("> "), AgentState::Idle);
|
||||
}
|
||||
|
||||
// ---- Kilo ----
|
||||
|
||||
#[test]
|
||||
fn kilo_waiting_question_prompt() {
|
||||
assert_eq!(
|
||||
detect_kilo(
|
||||
"Write the following joke to ~/joke.md?\n\
|
||||
1. Yes, write it\n\
|
||||
2. No, thanks\n\
|
||||
3. Type your own answer\n\
|
||||
↑↓ select enter submit esc dismiss",
|
||||
),
|
||||
AgentState::Blocked
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kilo_working() {
|
||||
assert_eq!(
|
||||
detect_kilo("Ask · DeepSeek V4 Pro\nesc interrupt\n12.8K (1%) · $0.01"),
|
||||
AgentState::Working
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kilo_idle() {
|
||||
assert_eq!(
|
||||
detect_kilo("Ask anything... \"Fix broken tests\"\nCode · DeepSeek V4 Pro"),
|
||||
AgentState::Idle
|
||||
);
|
||||
}
|
||||
|
||||
// ---- GitHub Copilot ----
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ pane_history = false
|
|||
# matches one of these names. Empty means apply to any focused pane.
|
||||
# If the list contains no valid names, the reveal does not apply.
|
||||
# Accepted: pi, claude, codex, gemini, cursor, cline, opencode, copilot,
|
||||
# kimi, kiro, droid, amp, grok, hermes, qodercli, qoder.
|
||||
# kimi, kiro, droid, amp, grok, hermes, kilo, qodercli, qoder.
|
||||
# cjk_ime_agents = []
|
||||
# Cursor shape rendered when reveal_hidden_cursor_for_cjk_ime is true.
|
||||
# Values: block, steady_block (default), underline, steady_underline, bar, steady_bar.
|
||||
|
|
|
|||
Loading…
Reference in New Issue