aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-04-10 15:14:18 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-04-10 15:14:45 +0300
commit31cf4c42014a8f24473f0ce5962ee57c2a8dcf67 (patch)
tree7c46826220ee9a91674cac838f0fa3daf7351f68
parentd96962adf6238b8c168df93315b7c8ef784415dd (diff)
fix: harden amp blocked detection
-rw-r--r--README.md2
-rw-r--r--src/detect.rs51
2 files changed, 48 insertions, 5 deletions
diff --git a/README.md b/README.md
index 40862c42..14a864be 100644
--- a/README.md
+++ b/README.md
@@ -141,7 +141,7 @@ the following agents have been tested:
| [claude code](https://docs.anthropic.com/en/docs/claude-code) | ✓ | ✓ | ✓ |
| [codex](https://github.com/openai/codex) | ✓ | ✓ | ✓ |
| [droid](https://factory.ai) | ✓ | ✓ | ✓ |
-| [amp](https://ampcode.com) | ✓ | ✓ | partial |
+| [amp](https://ampcode.com) | ✓ | ✓ | ✓ |
| [opencode](https://github.com/anomalyco/opencode) | ✓ | ✓ | ✓ |
heuristics also exist for these agents but have not been fully tested yet:
diff --git a/src/detect.rs b/src/detect.rs
index a026ddce..237d7270 100644
--- a/src/detect.rs
+++ b/src/detect.rs
@@ -349,18 +349,37 @@ fn detect_droid(content: &str) -> AgentState {
/// Amp (Sourcegraph) detection.
///
-/// Screen layout when working:
+/// Blocked approval prompts use a shared footer with options like
+/// "Approve", "Allow All for This Session", "Allow All for Every Session",
+/// "Allow File for Every Session", and "Deny with feedback". The header varies
+/// by approval type, for example "Invoke tool ...?", "Run this command?",
+/// "Allow editing file:", or "Allow creating file:".
+///
+/// Working layout:
/// ```text
/// ✓ Search Map the core runtime architecture...
/// ⋯ Oracle ▼
/// ≈ Running tools... Esc to cancel
/// ```
-///
-/// "Esc to cancel" is the reliable working indicator — it only appears
-/// while amp is actively running tools or thinking.
fn detect_amp(content: &str) -> AgentState {
let lower = content.to_lowercase();
+ let has_waiting_for_approval = lower.contains("waiting for approval");
+ let has_approval_header = lower.contains("invoke tool")
+ || lower.contains("run this command?")
+ || lower.contains("allow editing file:")
+ || lower.contains("allow creating file:")
+ || lower.contains("confirm tool call");
+ let has_approval_actions = lower.contains("approve")
+ && (lower.contains("allow all for this session")
+ || lower.contains("allow all for every session")
+ || lower.contains("allow file for every session")
+ || lower.contains("deny with feedback"));
+
+ if has_approval_actions && (has_waiting_for_approval || has_approval_header) {
+ return AgentState::Blocked;
+ }
+
if lower.contains("esc to cancel") {
return AgentState::Working;
}
@@ -1064,6 +1083,30 @@ mod tests {
// ---- Amp ----
#[test]
+ fn amp_blocked_waiting_for_approval() {
+ let screen = "Invoke tool shell_command?\n▸● Approve [Alt+1]\n ○ Allow All for This Session [Alt+2]\n ○ Allow All for Every Session [Alt+3]\n ○ Deny with feedback [Alt+4]\nWaiting for approval...";
+ assert_eq!(detect_state(Some(Agent::Amp), screen), AgentState::Blocked);
+ }
+
+ #[test]
+ fn amp_blocked_run_this_command() {
+ let screen = "Run this command?\nrg --files\n▸● Approve [Alt+1]\n ○ Allow All for This Session [Alt+2]\n ○ Allow All for Every Session [Alt+3]\n ○ Deny with feedback [Alt+4]";
+ assert_eq!(detect_state(Some(Agent::Amp), screen), AgentState::Blocked);
+ }
+
+ #[test]
+ fn amp_blocked_allow_editing_file() {
+ let screen = "Allow editing file:\nsrc/detect.rs\n▸● Approve [Alt+1]\n ○ Allow File for Every Session [Alt+2]\n ○ Allow All for This Session [Alt+3]\n ○ Deny with feedback [Alt+4]";
+ assert_eq!(detect_state(Some(Agent::Amp), screen), AgentState::Blocked);
+ }
+
+ #[test]
+ fn amp_blocked_allow_creating_file() {
+ let screen = "Allow creating file:\nsrc/new_file.rs\n▸● Approve [Alt+1]\n ○ Allow File for Every Session [Alt+2]\n ○ Allow All for This Session [Alt+3]\n ○ Deny with feedback [Alt+4]";
+ assert_eq!(detect_state(Some(Agent::Amp), screen), AgentState::Blocked);
+ }
+
+ #[test]
fn amp_working_running_tools() {
let screen = " ✓ Search Map the core runtime architecture\n ⋯ Oracle ▼\n ≈ Running tools... Esc to cancel";
assert_eq!(detect_state(Some(Agent::Amp), screen), AgentState::Working);