From b15898c2def14318f0a2fff5abed97a0c50b25fb Mon Sep 17 00:00:00 2001 From: onevcat Date: Sun, 19 Jul 2026 16:05:20 +0900 Subject: [PATCH] Fix OMP blocked prompt detection --- docs/components/agent-detection.md | 9 +++++---- .../AgentDetection/ScreenHeuristics.swift | 13 ++++++++++++- supacodeTests/ScreenHeuristicsTests.swift | 19 +++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/docs/components/agent-detection.md b/docs/components/agent-detection.md index bb1416cf9..a767395f4 100644 --- a/docs/components/agent-detection.md +++ b/docs/components/agent-detection.md @@ -32,10 +32,11 @@ points at a `~/.grok/` install (so Cursor's own `agent` entrypoint stays Cursor) process names / argv against known agent executables, scoring argv[0] highest, then process name, then command-line tokens. 2. **Screen heuristics.** It scans the last ~24 non-blank lines of the pane for - agent-specific UI cues — e.g. "Esc to interrupt", Oh My Pi's `Working… ⟦esc⟧` - loader or braille spinner status line (working), confirmation/permission prompts - (blocked), idle prompts. Each agent family has its own patterns (including spinner glyphs: - braille frames, symbol cycles, Cursor's hexagons, Kimi's moon phases, etc.). + agent-specific UI cues — e.g. "Esc to interrupt", Oh My Pi's + `Working… ⟦esc⟧` loader or braille spinner status line (working), its + interactive `Ask` choice prompt (blocked), confirmation/permission prompts + (blocked), idle prompts. Each agent family has its own patterns (including spinner + glyphs: braille frames, symbol cycles, Cursor's hexagons, Kimi's moon phases, etc.). For Claude, a running **background workflow** keeps a status line *below* the input box (e.g. `3/5 agents done · 7m 29s · ↓ 288.5k tokens`) after the turn has ended; Prowl reads that footer as **Working**, so a churning workflow isn't diff --git a/supacode/Infrastructure/AgentDetection/ScreenHeuristics.swift b/supacode/Infrastructure/AgentDetection/ScreenHeuristics.swift index b10e6b044..287752790 100644 --- a/supacode/Infrastructure/AgentDetection/ScreenHeuristics.swift +++ b/supacode/Infrastructure/AgentDetection/ScreenHeuristics.swift @@ -56,7 +56,18 @@ nonisolated private func recentLines(_ content: String, limit: Int) -> String { } nonisolated private func detectPi(_ content: String) -> AgentRawState { - hasPiWorkingLine(content) ? .working : .idle + if hasPiAskPrompt(content) { + return .blocked + } + return hasPiWorkingLine(content) ? .working : .idle +} + +nonisolated private func hasPiAskPrompt(_ content: String) -> Bool { + let lines = content.split(separator: "\n", omittingEmptySubsequences: false) + return lines.contains { line in + let trimmed = line.trimmingCharacters(in: .whitespaces) + return trimmed.contains("Enter select") && trimmed.contains("Esc cancel") + } } nonisolated private func hasPiWorkingLine(_ content: String) -> Bool { diff --git a/supacodeTests/ScreenHeuristicsTests.swift b/supacodeTests/ScreenHeuristicsTests.swift index f4a266307..c9a14a9d6 100644 --- a/supacodeTests/ScreenHeuristicsTests.swift +++ b/supacodeTests/ScreenHeuristicsTests.swift @@ -16,6 +16,25 @@ struct ScreenHeuristicsTests { #expect(DetectedAgent.pi.detectState(in: "Done") == .idle) } + @Test func piAskPromptIsBlocked() { + #expect( + DetectedAgent.pi.detectState( + in: """ + ⠏ Clarifying combined list order ⟨esc⟩ + + ╭─ Ask ─────────────────────────────────────────────────────────────────────╮ + │ Which order should the combined list use? │ + ├────────────────────────────────────────────────────────────────────────────┤ + │   Repo first │ + │  Global first │ + ├────────────────────────────────────────────────────────────────────────────┤ + │ Enter select · n note · ↑/↓ move · Esc cancel │ + ╰────────────────────────────────────────────────────────────────────────────╯ + """ + ) == .blocked + ) + } + @Test func piIgnoresStaleWorkingMentionInCompletedOutput() { #expect( DetectedAgent.pi.detectState(