feat(tui): implement PermissionsScreen with diff view #1307

Merged
freemo merged 1 commit from feature/m8-tui-permissions-screen into master 2026-04-02 17:08:13 +00:00
Owner

Summary

Implements the PermissionsScreen TUI widget for displaying tool permission requests with diff views, as specified in the TUI specification.

Changes

Domain Layer (src/cleveragents/tui/permissions/models.py)

  • DiffDisplayMode enum: unified, side_by_side, context
  • FileChangeType enum: M (modified), A (added), D (deleted)
  • PermissionDecision enum: allow_once, allow_always, reject_once, reject_always
  • PermissionRequest model: single file change with diff rendering methods
  • ToolPermissionRequest model: complete permission request with multiple file changes and decision tracking

Application Layer (src/cleveragents/tui/permissions/service.py)

  • PermissionRequestService: manages permission request queue and session-scoped decisions
    • Auto-resolves new requests when allow_always/reject_always session decision exists
    • Persists session-scoped decisions for the duration of the session

Presentation Layer (src/cleveragents/tui/permissions/screen.py)

  • PermissionsScreen widget: displays permission requests with split-pane layout
    • File list panel (left) with change type indicators [M], [A], [D]
    • Diff view panel (right) for selected file
    • Status bar with keyboard bindings
  • Keyboard bindings: a allow-once, A allow-always, r reject-once, R reject-always, j/k navigate, d cycle diff mode
  • 3 diff display modes: unified (default), side-by-side, context

Tests (features/tui_permissions_screen.feature)

  • 62 BDD scenarios covering all components
  • All mocks in features/mocks/ (none needed for this feature)
  • 98% coverage on new files

Quality Gates

  • nox -e lint: All checks passed
  • nox -e typecheck: 0 errors, 0 warnings
  • nox -e unit_tests -- features/tui_permissions_screen.feature: 62 scenarios passed

Closes #996

## Summary Implements the `PermissionsScreen` TUI widget for displaying tool permission requests with diff views, as specified in the TUI specification. ## Changes ### Domain Layer (`src/cleveragents/tui/permissions/models.py`) - `DiffDisplayMode` enum: `unified`, `side_by_side`, `context` - `FileChangeType` enum: `M` (modified), `A` (added), `D` (deleted) - `PermissionDecision` enum: `allow_once`, `allow_always`, `reject_once`, `reject_always` - `PermissionRequest` model: single file change with diff rendering methods - `ToolPermissionRequest` model: complete permission request with multiple file changes and decision tracking ### Application Layer (`src/cleveragents/tui/permissions/service.py`) - `PermissionRequestService`: manages permission request queue and session-scoped decisions - Auto-resolves new requests when `allow_always`/`reject_always` session decision exists - Persists session-scoped decisions for the duration of the session ### Presentation Layer (`src/cleveragents/tui/permissions/screen.py`) - `PermissionsScreen` widget: displays permission requests with split-pane layout - File list panel (left) with change type indicators `[M]`, `[A]`, `[D]` - Diff view panel (right) for selected file - Status bar with keyboard bindings - Keyboard bindings: `a` allow-once, `A` allow-always, `r` reject-once, `R` reject-always, `j`/`k` navigate, `d` cycle diff mode - 3 diff display modes: unified (default), side-by-side, context ### Tests (`features/tui_permissions_screen.feature`) - 62 BDD scenarios covering all components - All mocks in `features/mocks/` (none needed for this feature) - 98% coverage on new files ## Quality Gates - ✅ `nox -e lint`: All checks passed - ✅ `nox -e typecheck`: 0 errors, 0 warnings - ✅ `nox -e unit_tests -- features/tui_permissions_screen.feature`: 62 scenarios passed Closes #996
feat(tui): implement PermissionsScreen with diff view
Some checks failed
CI / lint (pull_request) Failing after 2s
CI / typecheck (pull_request) Failing after 2s
CI / coverage (pull_request) Has been skipped
CI / security (pull_request) Failing after 1s
CI / quality (pull_request) Failing after 1s
CI / integration_tests (pull_request) Failing after 1s
CI / e2e_tests (pull_request) Failing after 1s
CI / build (pull_request) Failing after 2s
CI / helm (pull_request) Failing after 2s
CI / unit_tests (pull_request) Successful in 5m55s
CI / docker (pull_request) Has been skipped
CI / status-check (pull_request) Failing after 1s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Has been skipped
1e17c4aa64
Implement PermissionsScreen with diff view for tool permission requests.
- 3 diff display modes (unified, side-by-side, raw)
- Allow/reject keyboard bindings
- Permission decision persistence

ISSUES CLOSED: #996
Author
Owner

Review claimed by reviewer pool instance reviewer-pool-1. Dispatching independent code review.

Review claimed by reviewer pool instance reviewer-pool-1. Dispatching independent code review.
freemo added this to the v3.7.0 milestone 2026-04-02 17:07:31 +00:00
Author
Owner

Code Review — APPROVED

Summary

Clean, well-structured implementation of the PermissionsScreen TUI widget with proper domain/application/presentation layer separation. The code is fully typed, follows existing codebase patterns, and includes comprehensive BDD test coverage (62 scenarios).

What was reviewed

  • 6 new files (1604 lines total): models, service, screen, package init, feature file, step definitions
  • Spec alignment against issue #996 and M8 TUI milestone scope
  • Type safety, API consistency, test quality, correctness, security

Strengths

  1. Architecture: Excellent separation of concerns — domain models (models.py), application service (service.py), and presentation (screen.py) are cleanly decoupled.
  2. Immutability: apply_decision() returns a new instance via model_copy() rather than mutating in place — good defensive pattern.
  3. Session-scoped decisions: The PermissionRequestService auto-resolution of allow_always/reject_always is well-designed and correctly tested.
  4. Test coverage: 62 BDD scenarios covering enums, models, service queue/decision logic, screen widget navigation/rendering, and edge cases (empty changes, wrap-around, delete-only/insert-only diffs).
  5. Textual fallback: The _load_static_base() pattern gracefully handles environments without Textual installed.

Non-blocking observations (for future follow-up)

  1. Inline import difflib in models.py (lines 91, 104, 142): The difflib import appears inside 3 methods rather than at the top of the file. The rest of the codebase (repl.py, diff_review.py, fs_directory.py, fuzzy.py) consistently imports difflib at module level. Consider moving to the top for consistency.
  2. Step file length: features/steps/tui_permissions_screen_steps.py is 618 lines, slightly over the 500-line guideline. If this grows further, consider splitting into multiple step files by component.
  3. Broad exception catch in screen.py line 32: except Exception in _load_static_base() could be narrowed to except (ImportError, ModuleNotFoundError) for precision.

Metadata fixes applied

  • Added Type/Feature label (was missing)
  • Assigned to v3.7.0 milestone (matching issue #996)

Verdict

The implementation is solid, well-tested, and aligns with the TUI specification. The non-blocking observations are minor style/consistency items that don't warrant blocking the merge. Approved for merge.

## Code Review — APPROVED ✅ ### Summary Clean, well-structured implementation of the `PermissionsScreen` TUI widget with proper domain/application/presentation layer separation. The code is fully typed, follows existing codebase patterns, and includes comprehensive BDD test coverage (62 scenarios). ### What was reviewed - **6 new files** (1604 lines total): models, service, screen, package init, feature file, step definitions - Spec alignment against issue #996 and M8 TUI milestone scope - Type safety, API consistency, test quality, correctness, security ### Strengths 1. **Architecture**: Excellent separation of concerns — domain models (`models.py`), application service (`service.py`), and presentation (`screen.py`) are cleanly decoupled. 2. **Immutability**: `apply_decision()` returns a new instance via `model_copy()` rather than mutating in place — good defensive pattern. 3. **Session-scoped decisions**: The `PermissionRequestService` auto-resolution of `allow_always`/`reject_always` is well-designed and correctly tested. 4. **Test coverage**: 62 BDD scenarios covering enums, models, service queue/decision logic, screen widget navigation/rendering, and edge cases (empty changes, wrap-around, delete-only/insert-only diffs). 5. **Textual fallback**: The `_load_static_base()` pattern gracefully handles environments without Textual installed. ### Non-blocking observations (for future follow-up) 1. **Inline `import difflib`** in `models.py` (lines 91, 104, 142): The `difflib` import appears inside 3 methods rather than at the top of the file. The rest of the codebase (`repl.py`, `diff_review.py`, `fs_directory.py`, `fuzzy.py`) consistently imports `difflib` at module level. Consider moving to the top for consistency. 2. **Step file length**: `features/steps/tui_permissions_screen_steps.py` is 618 lines, slightly over the 500-line guideline. If this grows further, consider splitting into multiple step files by component. 3. **Broad exception catch** in `screen.py` line 32: `except Exception` in `_load_static_base()` could be narrowed to `except (ImportError, ModuleNotFoundError)` for precision. ### Metadata fixes applied - Added `Type/Feature` label (was missing) - Assigned to `v3.7.0` milestone (matching issue #996) ### Verdict The implementation is solid, well-tested, and aligns with the TUI specification. The non-blocking observations are minor style/consistency items that don't warrant blocking the merge. **Approved for merge.**
freemo merged commit 4a18a15ca5 into master 2026-04-02 17:08:13 +00:00
freemo deleted branch feature/m8-tui-permissions-screen 2026-04-02 17:08:16 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core!1307
No description provided.