aboutsummaryrefslogtreecommitdiff
path: root/src/integration
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-20 15:17:54 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-20 15:18:03 +0300
commit28b628d79d755afbb3ac45f9184a03c204c26784 (patch)
tree93ee9f4c9939430c5e82b22da7c080f99f882fe0 /src/integration
parent9450b168c727e9e4cbee95e6edf4f11cfe6f2154 (diff)
fix: report kimi questions as blocked
Diffstat (limited to 'src/integration')
-rw-r--r--src/integration/assets/kimi/herdr-agent-state.ps12
-rw-r--r--src/integration/assets/kimi/herdr-agent-state.sh2
-rw-r--r--src/integration/config_edit.rs16
-rw-r--r--src/integration/mod.rs39
-rw-r--r--src/integration/tests.rs35
5 files changed, 73 insertions, 21 deletions
diff --git a/src/integration/assets/kimi/herdr-agent-state.ps1 b/src/integration/assets/kimi/herdr-agent-state.ps1
index ff6bcefe..16c9eb4d 100644
--- a/src/integration/assets/kimi/herdr-agent-state.ps1
+++ b/src/integration/assets/kimi/herdr-agent-state.ps1
@@ -2,7 +2,7 @@
# managed by herdr; reinstalling or updating the integration overwrites this file.
# add custom hooks beside this file instead of editing it.
# HERDR_INTEGRATION_ID=kimi
-# HERDR_INTEGRATION_VERSION=4
+# HERDR_INTEGRATION_VERSION=5
param([string]$Action = "")
diff --git a/src/integration/assets/kimi/herdr-agent-state.sh b/src/integration/assets/kimi/herdr-agent-state.sh
index b5b6cc4b..9c307b4a 100644
--- a/src/integration/assets/kimi/herdr-agent-state.sh
+++ b/src/integration/assets/kimi/herdr-agent-state.sh
@@ -3,7 +3,7 @@
# managed by herdr; reinstalling or updating the integration overwrites this file.
# add custom hooks beside this file instead of editing it.
# HERDR_INTEGRATION_ID=kimi
-# HERDR_INTEGRATION_VERSION=4
+# HERDR_INTEGRATION_VERSION=5
set -eu
diff --git a/src/integration/config_edit.rs b/src/integration/config_edit.rs
index 63c18845..630682ce 100644
--- a/src/integration/config_edit.rs
+++ b/src/integration/config_edit.rs
@@ -749,18 +749,26 @@ pub(crate) fn build_kimi_config_with_hooks(content: &str, hook_path: &Path) -> S
result.push_str(KIMI_CONFIG_BLOCK_BEGIN);
result.push('\n');
- for (event, action) in KIMI_HOOK_EVENTS {
- result.push_str(&kimi_hook_table(event, hook_path, action));
+ for (event, matcher, action) in KIMI_HOOK_EVENTS {
+ result.push_str(&kimi_hook_table(event, matcher, hook_path, action));
}
result.push_str(KIMI_CONFIG_BLOCK_END);
result.push('\n');
result
}
-pub(crate) fn kimi_hook_table(event: &str, hook_path: &Path, action: &str) -> String {
+pub(crate) fn kimi_hook_table(
+ event: &str,
+ matcher: Option<&str>,
+ hook_path: &Path,
+ action: &str,
+) -> String {
let command = hook_command(hook_path, Some(action));
+ let matcher = matcher
+ .map(|matcher| format!("matcher = {}\n", toml_basic_string(matcher)))
+ .unwrap_or_default();
format!(
- "[[hooks]]\nevent = {}\ncommand = {}\ntimeout = 10\n\n",
+ "[[hooks]]\nevent = {}\n{matcher}command = {}\ntimeout = 10\n\n",
toml_basic_string(event),
toml_basic_string(&command)
)
diff --git a/src/integration/mod.rs b/src/integration/mod.rs
index fdc1c5bd..73c23fc6 100644
--- a/src/integration/mod.rs
+++ b/src/integration/mod.rs
@@ -58,20 +58,37 @@ const KIMI_HOOK_ASSET: &str = if cfg!(windows) {
} else {
include_str!("assets/kimi/herdr-agent-state.sh")
};
-const KIMI_INTEGRATION_VERSION: u32 = 4;
+const KIMI_INTEGRATION_VERSION: u32 = 5;
const KIMI_CONFIG_BLOCK_BEGIN: &str = "# >>> herdr kimi integration";
const KIMI_CONFIG_BLOCK_END: &str = "# <<< herdr kimi integration";
const KIMI_MIN_VERSION: &str = "0.14.0";
-const KIMI_HOOK_EVENTS: [(&str, &str); 9] = [
- ("SessionStart", "session"),
- ("UserPromptSubmit", "working"),
- ("PreToolUse", "working"),
- ("SubagentStart", "working"),
- ("PreCompact", "working"),
- ("PermissionRequest", "blocked"),
- ("PermissionResult", "working"),
- ("Stop", "idle"),
- ("Interrupt", "idle"),
+const KIMI_ASK_USER_QUESTION_MATCHER: &str = "^AskUserQuestion$";
+const KIMI_OTHER_TOOL_MATCHER: &str = "^(?!AskUserQuestion$).*$";
+const KIMI_HOOK_EVENTS: [(&str, Option<&str>, &str); 12] = [
+ ("SessionStart", None, "session"),
+ ("UserPromptSubmit", None, "working"),
+ ("PreToolUse", Some(KIMI_OTHER_TOOL_MATCHER), "working"),
+ (
+ "PreToolUse",
+ Some(KIMI_ASK_USER_QUESTION_MATCHER),
+ "blocked",
+ ),
+ (
+ "PostToolUse",
+ Some(KIMI_ASK_USER_QUESTION_MATCHER),
+ "working",
+ ),
+ (
+ "PostToolUseFailure",
+ Some(KIMI_ASK_USER_QUESTION_MATCHER),
+ "working",
+ ),
+ ("SubagentStart", None, "working"),
+ ("PreCompact", None, "working"),
+ ("PermissionRequest", None, "blocked"),
+ ("PermissionResult", None, "working"),
+ ("Stop", None, "idle"),
+ ("Interrupt", None, "idle"),
];
const COPILOT_HOOK_INSTALL_NAME: &str = if cfg!(windows) {
"herdr-agent-state.ps1"
diff --git a/src/integration/tests.rs b/src/integration/tests.rs
index 41714ffa..786e67fb 100644
--- a/src/integration/tests.rs
+++ b/src/integration/tests.rs
@@ -116,16 +116,23 @@ fn kimi_config_hooks(config: &str) -> Vec<toml::Value> {
.unwrap_or_default()
}
-fn assert_kimi_hook(config: &str, hook_path: &Path, event: &str, action: &str) {
+fn assert_kimi_hook(
+ config: &str,
+ hook_path: &Path,
+ event: &str,
+ matcher: Option<&str>,
+ action: &str,
+) {
let command = kimi_hook_command(hook_path, action);
let hooks = kimi_config_hooks(config);
assert!(
hooks.iter().any(|hook| {
hook.get("event").and_then(toml::Value::as_str) == Some(event)
+ && hook.get("matcher").and_then(toml::Value::as_str) == matcher
&& hook.get("command").and_then(toml::Value::as_str) == Some(command.as_str())
&& hook.get("timeout").and_then(toml::Value::as_integer) == Some(10)
}),
- "missing kimi hook for {event} -> {action}"
+ "missing kimi hook for {event} ({matcher:?}) -> {action}"
);
}
@@ -1434,8 +1441,8 @@ fn install_kimi_writes_hook_and_updates_config() {
assert!(config.contains("command = \"echo keep\""));
assert!(config.contains(KIMI_CONFIG_BLOCK_BEGIN));
assert!(config.contains(KIMI_CONFIG_BLOCK_END));
- for (event, action) in KIMI_HOOK_EVENTS {
- assert_kimi_hook(&config, &installed.hook_path, event, action);
+ for (event, matcher, action) in KIMI_HOOK_EVENTS {
+ assert_kimi_hook(&config, &installed.hook_path, event, matcher, action);
}
std::env::remove_var("HOME");
@@ -1443,6 +1450,26 @@ fn install_kimi_writes_hook_and_updates_config() {
}
#[test]
+fn kimi_question_hooks_report_blocked_until_the_question_finishes() {
+ assert!(KIMI_HOOK_EVENTS.contains(&(
+ "PreToolUse",
+ Some(KIMI_ASK_USER_QUESTION_MATCHER),
+ "blocked",
+ )));
+ assert!(KIMI_HOOK_EVENTS.contains(&(
+ "PostToolUse",
+ Some(KIMI_ASK_USER_QUESTION_MATCHER),
+ "working",
+ )));
+ assert!(KIMI_HOOK_EVENTS.contains(&(
+ "PostToolUseFailure",
+ Some(KIMI_ASK_USER_QUESTION_MATCHER),
+ "working",
+ )));
+ assert!(KIMI_HOOK_EVENTS.contains(&("PreToolUse", Some(KIMI_OTHER_TOOL_MATCHER), "working",)));
+}
+
+#[test]
fn install_kimi_uses_kimi_code_home_env() {
let _lock = integration_env_lock();
let base = unique_base();