aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-06-01 03:50:45 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-06-01 04:16:36 +0300
commit1d56cd0e18fc69a85a0889ca6f9a9f3069a4be3a (patch)
treef18bc80137a6dcfbccc7aa3666b94649197dbae5 /src
parent2fcf9b678d0f154b2d41aa5fafa25aaa73ec7f17 (diff)
feat: detect kilo code cli
refs #270
Diffstat (limited to 'src')
-rw-r--r--src/config/model.rs3
-rw-r--r--src/config/sound.rs3
-rw-r--r--src/detect/agents/kilo.rs9
-rw-r--r--src/detect/agents/mod.rs2
-rw-r--r--src/detect/mod.rs50
-rw-r--r--src/main.rs2
6 files changed, 67 insertions, 2 deletions
diff --git a/src/config/model.rs b/src/config/model.rs
index 0776e09b..c312acfa 100644
--- a/src/config/model.rs
+++ b/src/config/model.rs
@@ -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".
diff --git a/src/config/sound.rs b/src/config/sound.rs
index e4f15108..50b2355b 100644
--- a/src/config/sound.rs
+++ b/src/config/sound.rs
@@ -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,
}
}
diff --git a/src/detect/agents/kilo.rs b/src/detect/agents/kilo.rs
new file mode 100644
index 00000000..1ab3651a
--- /dev/null
+++ b/src/detect/agents/kilo.rs
@@ -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)
+}
diff --git a/src/detect/agents/mod.rs b/src/detect/agents/mod.rs
index 87b4043f..4597c122 100644
--- a/src/detect/agents/mod.rs
+++ b/src/detect/agents/mod.rs
@@ -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),
};
diff --git a/src/detect/mod.rs b/src/detect/mod.rs
index cf600f51..b9806b19 100644
--- a/src/detect/mod.rs
+++ b/src/detect/mod.rs
@@ -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]
diff --git a/src/main.rs b/src/main.rs
index b317c2da..b7b11b16 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -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.