Feature: Permission Question Widget As a TUI user I want an inline permission question widget So that I can allow or reject single-file operations without leaving the conversation stream Background: Given the permission question widget module is imported # ── Domain model ────────────────────────────────────────────────────────── Scenario: Create InlinePermissionQuestion with file path and type When I create an InlinePermissionQuestion for "src/auth/handler.py" with type "file_write" Then the question file path should be "src/auth/handler.py" And the question request type should be "file_write" And the question has_diff should be False Scenario: InlinePermissionQuestion with diff content Given an InlinePermissionQuestion for "src/main.py" with type "file_write" and diff "@@ -1,3 +1,4 @@\n+import os" Then the question has_diff should be True Scenario: InlinePermissionQuestion description_line for file_write When I create an InlinePermissionQuestion for "src/auth/handler.py" with type "file_write" Then the description line should contain "write to" Scenario: InlinePermissionQuestion description_line for file_delete When I create an InlinePermissionQuestion for "src/old.py" with type "file_delete" Then the description line should contain "delete" Scenario: InlinePermissionQuestion description_line for shell_exec When I create an InlinePermissionQuestion for "make test" with type "shell_exec" Then the description line should contain "execute" # ── Widget creation ─────────────────────────────────────────────────────── Scenario: Widget creation renders permission request When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" Then the widget text should contain "Permission Required" And the widget text should contain "src/auth/handler.py" And the widget text should contain "Allow once" And the widget text should contain "Reject once" Scenario: Widget creation shows diff hint when no diff When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" Then the widget text should contain "PermissionsScreen" Scenario: Widget creation with diff content shows diff hint Given a PermissionQuestionWidget for "src/main.py" with type "file_write" and diff "@@ -1 +1 @@\n+x=1" Then the widget text should contain "PermissionsScreen" Scenario: Widget creation with diff content renders diff by default Given a PermissionQuestionWidget for "src/main.py" with type "file_write" and diff "@@ -1 +1 @@\n+x=1" Then the widget text should contain "── diff ──" And the widget text should contain "+x=1" And the widget show_diff property should be True Scenario: Widget diff visibility can be toggled off Given a PermissionQuestionWidget for "src/main.py" with type "file_write" and diff "@@ -1 +1 @@\n+x=1" When I set the widget show_diff flag to False Then the widget text should not contain "── diff ──" And the widget show_diff property should be False Scenario: Widget diff visibility can be toggled on after hiding Given a PermissionQuestionWidget for "src/main.py" with type "file_write" and diff "@@ -1 +1 @@\n+x=1" When I set the widget show_diff flag to False And I set the widget show_diff flag to True Then the widget text should contain "── diff ──" And the widget show_diff property should be True Scenario: Widget show_diff property stays False without diff content When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" Then the widget show_diff property should be False When I set the widget show_diff flag to True Then the widget show_diff property should be False # ── Allow action ────────────────────────────────────────────────────────── Scenario: Allow once via key "a" When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" And I press key "a" on the widget Then a PermissionDecisionEvent should be returned And the decision should be "allow_once" Scenario: Allow always via key "A" When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" And I press key "A" on the widget Then a PermissionDecisionEvent should be returned And the decision should be "allow_always" Scenario: Allow once via enter on first option When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" And I press key "enter" on the widget Then a PermissionDecisionEvent should be returned And the decision should be "allow_once" # ── Reject action ───────────────────────────────────────────────────────── Scenario: Reject once via key "r" When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" And I press key "r" on the widget Then a PermissionDecisionEvent should be returned And the decision should be "reject_once" Scenario: Reject always via key "R" When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" And I press key "R" on the widget Then a PermissionDecisionEvent should be returned And the decision should be "reject_always" # ── Navigation ──────────────────────────────────────────────────────────── Scenario: Navigate down moves selection When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" And I press key "down" on the widget Then the widget selected index should be 1 And no decision event should be returned Scenario: Navigate up wraps around When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" And I press key "up" on the widget Then the widget selected index should be 3 Scenario: Navigate down then enter selects second option When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" And I press key "down" on the widget And I press key "enter" on the widget Then a PermissionDecisionEvent should be returned And the decision should be "allow_always" Scenario: Navigate down twice then enter selects third option When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" And I press key "down" on the widget And I press key "down" on the widget And I press key "enter" on the widget Then a PermissionDecisionEvent should be returned And the decision should be "reject_once" # ── Open full screen ────────────────────────────────────────────────────── Scenario: Press v sets open_full_screen flag When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" And I press key "v" on the widget Then the open_full_screen flag should be True And no decision event should be returned # ── Unknown key ─────────────────────────────────────────────────────────── Scenario: Unknown key returns None When I create a PermissionQuestionWidget for "src/auth/handler.py" with type "file_write" And I press key "x" on the widget Then no decision event should be returned # ── Inline rendering in conversation ───────────────────────────────────── Scenario: render_permission_question returns correct structure When I render a permission question for "src/auth/handler.py" with type "file_write" Then the permission question rendered text should contain "Permission Required" And the permission question rendered text should contain "src/auth/handler.py" And the permission question rendered text should contain "Allow once" Scenario: render_permission_question with selected_index 2 highlights third option When I render a permission question for "src/auth/handler.py" with type "file_write" at index 2 Then the permission question rendered text should contain "Reject once" Scenario: render_permission_question with diff shows diff content when show_diff is True Given a permission question for "src/main.py" with type "file_write" and diff "+import os" rendered at index 0 with show_diff Then the permission question rendered text should contain "+import os" # ── Widget exports ──────────────────────────────────────────────────────── Scenario: PermissionQuestionWidget is exported from tui.widgets Then PermissionQuestionWidget should be importable from tui.widgets And PermissionDecisionEvent should be importable from tui.widgets And render_permission_question should be importable from tui.widgets # ── Domain model exports ────────────────────────────────────────────────── Scenario: InlinePermissionQuestion is exported from domain.models.core Then InlinePermissionQuestion should be importable from domain.models.core And PermissionDecision should be importable from domain.models.core And PermissionRequestType should be importable from domain.models.core