Skip to content

fix: prevent permission prompt pattern from matching stale prompts#69

Merged
haofeif merged 1 commit into
awslabs:mainfrom
sriharshaarangi:fix/permission-prompt-stale
Feb 8, 2026
Merged

fix: prevent permission prompt pattern from matching stale prompts#69
haofeif merged 1 commit into
awslabs:mainfrom
sriharshaarangi:fix/permission-prompt-stale

Conversation

@sriharshaarangi

Copy link
Copy Markdown
Contributor

Fixes #68

Problem

After PR #61 removed the $ anchor from idle_prompt_pattern, the combined permission_prompt_pattern matches stale [y/n/t]: text in scrollback. \s* between ]: and the idle prompt bridges across \n characters, connecting old permission prompts with the current idle prompt. This causes get_status() to permanently return WAITING_USER_ANSWER after any permission prompt interaction.

Fix

Replace \s* with [ \t]* in the permission prompt pattern in both kiro_cli.py and q_cli.py:

# Before:
r"Allow this action\?.*\[.*y.*\/.*n.*\/.*t.*\]:\s*" + self._idle_prompt_pattern

# After:
r"Allow this action\?.*\[.*y.*\/.*n.*\/.*t.*\]:[ \t]*" + self._idle_prompt_pattern

[ \t]* only matches horizontal whitespace (spaces and tabs), blocking newline bridging.

re.DOTALL is intentionally kept — it is needed for narrow terminals where the permission prompt text wraps across lines.

Testing

  • Added unit test test_stale_permission_prompt_not_matched verifying stale prompts do not match
  • Full test suite: 190 passed, 9 skipped
  • E2E verified: trigger permission prompt → answer y → status correctly returns completed (not waiting_user_answer)
  • Inbox messages deliver correctly after permission prompt interaction

@haofeif haofeif added the bug Something isn't working label Feb 8, 2026
@codecov-commenter

codecov-commenter commented Feb 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@f588e6a). Learn more about missing BASE report.

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #69   +/-   ##
=======================================
  Coverage        ?   20.17%           
=======================================
  Files           ?       30           
  Lines           ?     1403           
  Branches        ?        0           
=======================================
  Hits            ?      283           
  Misses          ?     1120           
  Partials        ?        0           
Flag Coverage Δ
unittests 20.17% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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
@sriharshaarangi sriharshaarangi force-pushed the fix/permission-prompt-stale branch from 459ea8a to 1ff08ab Compare February 8, 2026 12:06
@haofeif haofeif requested review from a team and anilkmr-a2z February 8, 2026 12:31
@haofeif haofeif merged commit 4e27dc1 into awslabs:main Feb 8, 2026
9 checks passed
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: stale permission prompt in scrollback causes false waiting_user_answer status

4 participants