fix: prevent permission prompt pattern from matching stale prompts#69
Merged
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #69 +/- ##
=======================================
Coverage ? 20.17%
=======================================
Files ? 30
Lines ? 1403
Branches ? 0
=======================================
Hits ? 283
Misses ? 1120
Partials ? 0
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
The permission_prompt_pattern falsely matched stale 'Allow this action? [y/n/t]:' text in terminal history, causing status to return WAITING_USER_ANSWER instead of IDLE. This blocked inbox message delivery. Root cause: PR awslabs#61 removed the $ anchor from idle_prompt_pattern. The anchor previously prevented stale [y/n/t]: from matching because the adjacent idle prompt wasn't at end-of-string. Without it, \s* between ]: and the idle prompt bridged across newlines to match stale prompts. Fix: Replace \s* with [ \t]* so the pattern only bridges spaces/tabs, not newlines. re.DOTALL is intentionally kept — the permission prompt text can wrap across lines in narrow terminals, so .* must span newlines to match [y/n/t]: on a different line than 'Allow this action?'. Changes: - kiro_cli.py: \s* -> [ \t]* in permission_prompt_pattern - q_cli.py: same fix - test_kiro_cli_unit.py: add test for stale permission prompt rejection
459ea8a to
1ff08ab
Compare
tuanknguyen
approved these changes
Feb 8, 2026
sriharshaarangi
added a commit
to sriharshaarangi/cli-agent-orchestrator
that referenced
this pull request
Feb 10, 2026
Decouple permission pattern from idle pattern in get_status(). Count idle prompt lines after last [y/n/t]: to distinguish active (<=1 line) from stale (>1 lines) permission prompts. Previous approaches failed because: - awslabs#69: [ \t]* can't bridge newlines, active prompts never detected - awslabs#61: \s* bridges newlines but also matches stale prompts Line-based counting handles \r redraws correctly (same line, no \n) and uses the LAST [y/n/t]: match to handle re-rendered prompts. Applied to both kiro_cli.py and q_cli.py. Includes 24 unit tests with real terminal fixtures and 7 integration tests against real kiro-cli (opt-in live view via CAO_TEST_WATCH=1).
sriharshaarangi
added a commit
to sriharshaarangi/cli-agent-orchestrator
that referenced
this pull request
Feb 10, 2026
Decouple permission pattern from idle pattern in get_status(). Count idle prompt lines after last [y/n/t]: to distinguish active (<=1 line) from stale (>1 lines) permission prompts. Previous approaches failed because: - awslabs#69: [ \t]* can't bridge newlines, active prompts never detected - awslabs#61: \s* bridges newlines but also matches stale prompts Line-based counting handles \r redraws correctly (same line, no \n) and uses the LAST [y/n/t]: match to handle re-rendered prompts. Applied to both kiro_cli.py and q_cli.py. Unit tests (24 tests, test_permission_prompt_detection.py): Category | Our Fix | awslabs#61 | awslabs#69 Active prompts (P1-P4,P8) | 5/5 | 5/5 | 0/5 Stale prompts (P5-P7) | 4/4 | 0/4 | 4/4* Non-permission (N1-N9) | 8/8 | 8/8 | 8/8 Edge cases (ANSI, multi) | 7/7 | 4/7 | 4/7 Total | 24/24 | 18/24 | 15/24 * awslabs#69 stale tests pass only because prompts are never detected. Integration tests (7 tests, test_kiro_cli_integration.py, real kiro-cli): Test | Our Fix | awslabs#61 | awslabs#69 P1/P2 active | PASS | PASS | FAIL (IDLE) P3/P4 injection | PASS | PASS | FAIL (IDLE) P5/P6 stale | PASS | FAIL (WAITING_USER_ANSWER) | PASS* P7 multiple prompts | PASS | FAIL (never completes) | FAIL (not detected) N4/N5 processing | PASS | PASS | PASS INIT smoke | PASS | PASS | PASS QUERY smoke | PASS | PASS | PASS Total | 7/7 | 5/7 | 4/7 * awslabs#69 P5/P6 passes for wrong reason (nothing ever matches). Opt-in live terminal view via CAO_TEST_WATCH=1.
sriharshaarangi
added a commit
to sriharshaarangi/cli-agent-orchestrator
that referenced
this pull request
Feb 10, 2026
Decouple permission pattern from idle pattern in get_status(). Count idle prompt lines after last [y/n/t]: to distinguish active (<=1 line) from stale (>1 lines) permission prompts. Previous approaches failed because: - awslabs#69: [ \t]* can't bridge newlines, active prompts never detected - awslabs#61: \s* bridges newlines but also matches stale prompts Line-based counting handles \r redraws correctly (same line, no \n) and uses the LAST [y/n/t]: match to handle re-rendered prompts. Applied to both kiro_cli.py and q_cli.py. Unit tests (24 tests, test_permission_prompt_detection.py): Category | Our Fix | awslabs#61 | awslabs#69 Active prompts (P1-P4,P8) | 5/5 | 5/5 | 0/5 Stale prompts (P5-P7) | 4/4 | 0/4 | 4/4* Non-permission (N1-N9) | 8/8 | 8/8 | 8/8 Edge cases (ANSI, multi) | 7/7 | 4/7 | 4/7 Total | 24/24 | 18/24 | 15/24 * awslabs#69 stale tests pass only because prompts are never detected. Integration tests (7 tests, test_kiro_cli_integration.py, real kiro-cli): Test | Our Fix | awslabs#61 | awslabs#69 P1/P2 active | PASS | PASS | FAIL (IDLE) P3/P4 injection | PASS | PASS | FAIL (IDLE) P5/P6 stale | PASS | FAIL (WAITING_USER_ANSWER) | PASS* P7 multiple prompts | PASS | FAIL (never completes) | FAIL (not detected) N4/N5 processing | PASS | PASS | PASS INIT smoke | PASS | PASS | PASS QUERY smoke | PASS | PASS | PASS Total | 7/7 | 5/7 | 4/7 * awslabs#69 P5/P6 passes for wrong reason (nothing ever matches). Opt-in live terminal view via CAO_TEST_WATCH=1.
sriharshaarangi
added a commit
to sriharshaarangi/cli-agent-orchestrator
that referenced
this pull request
Feb 10, 2026
Decouple permission pattern from idle pattern in get_status(). Count idle prompt lines after last [y/n/t]: to distinguish active (<=1 line) from stale (>1 lines) permission prompts. Previous approaches failed because: - awslabs#69: [ \t]* can't bridge newlines, active prompts never detected - awslabs#61: \s* bridges newlines but also matches stale prompts Line-based counting handles \r redraws correctly (same line, no \n) and uses the LAST [y/n/t]: match to handle re-rendered prompts. Applied to both kiro_cli.py and q_cli.py. Unit tests (24 tests, test_permission_prompt_detection.py): Category | Our Fix | awslabs#61 | awslabs#69 Active prompts (P1-P4,P8) | 5/5 | 5/5 | 0/5 Stale prompts (P5-P7) | 4/4 | 0/4 | 4/4* Non-permission (N1-N9) | 8/8 | 8/8 | 8/8 Edge cases (ANSI, multi) | 7/7 | 4/7 | 4/7 Total | 24/24 | 18/24 | 15/24 * awslabs#69 stale tests pass only because prompts are never detected. Integration tests (7 tests, test_kiro_cli_integration.py, real kiro-cli): Test | Our Fix | awslabs#61 | awslabs#69 P1/P2 active | PASS | PASS | FAIL (IDLE) P3/P4 injection | PASS | PASS | FAIL (IDLE) P5/P6 stale | PASS | FAIL (WAITING_USER_ANSWER) | PASS* P7 multiple prompts | PASS | FAIL (never completes) | FAIL (not detected) N4/N5 processing | PASS | PASS | PASS INIT smoke | PASS | PASS | PASS QUERY smoke | PASS | PASS | PASS Total | 7/7 | 5/7 | 4/7 * awslabs#69 P5/P6 passes for wrong reason (nothing ever matches). Opt-in live terminal view via CAO_TEST_WATCH=1.
haofeif
pushed a commit
that referenced
this pull request
Feb 16, 2026
Decouple permission pattern from idle pattern in get_status(). Count idle prompt lines after last [y/n/t]: to distinguish active (<=1 line) from stale (>1 lines) permission prompts. Previous approaches failed because: - #69: [ \t]* can't bridge newlines, active prompts never detected - #61: \s* bridges newlines but also matches stale prompts Line-based counting handles \r redraws correctly (same line, no \n) and uses the LAST [y/n/t]: match to handle re-rendered prompts. Applied to both kiro_cli.py and q_cli.py. Unit tests (24 tests, test_permission_prompt_detection.py): Category | Our Fix | #61 | #69 Active prompts (P1-P4,P8) | 5/5 | 5/5 | 0/5 Stale prompts (P5-P7) | 4/4 | 0/4 | 4/4* Non-permission (N1-N9) | 8/8 | 8/8 | 8/8 Edge cases (ANSI, multi) | 7/7 | 4/7 | 4/7 Total | 24/24 | 18/24 | 15/24 * #69 stale tests pass only because prompts are never detected. Integration tests (7 tests, test_kiro_cli_integration.py, real kiro-cli): Test | Our Fix | #61 | #69 P1/P2 active | PASS | PASS | FAIL (IDLE) P3/P4 injection | PASS | PASS | FAIL (IDLE) P5/P6 stale | PASS | FAIL (WAITING_USER_ANSWER) | PASS* P7 multiple prompts | PASS | FAIL (never completes) | FAIL (not detected) N4/N5 processing | PASS | PASS | PASS INIT smoke | PASS | PASS | PASS QUERY smoke | PASS | PASS | PASS Total | 7/7 | 5/7 | 4/7 * #69 P5/P6 passes for wrong reason (nothing ever matches). Opt-in live terminal view via CAO_TEST_WATCH=1.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #68
Problem
After PR #61 removed the
$anchor fromidle_prompt_pattern, the combinedpermission_prompt_patternmatches stale[y/n/t]:text in scrollback.\s*between]:and the idle prompt bridges across\ncharacters, connecting old permission prompts with the current idle prompt. This causesget_status()to permanently returnWAITING_USER_ANSWERafter any permission prompt interaction.Fix
Replace
\s*with[ \t]*in the permission prompt pattern in bothkiro_cli.pyandq_cli.py:[ \t]*only matches horizontal whitespace (spaces and tabs), blocking newline bridging.re.DOTALLis intentionally kept — it is needed for narrow terminals where the permission prompt text wraps across lines.Testing
test_stale_permission_prompt_not_matchedverifying stale prompts do not matchy→ status correctly returnscompleted(notwaiting_user_answer)