docs(spec): document inline PermissionQuestionWidget for single-file permission requests

Add inline permission question widget section to TUI documentation in
docs/specification.md and update ADR-044 Prompt Architecture section to
distinguish between single-file (inline widget) and multi-file
(PermissionsScreen) permission request handling.

Changes:
- docs/specification.md: Add '### Inline Permission Question Widget' section
  documenting PermissionQuestionWidget, InlinePermissionQuestion domain model,
  PermissionRequestType enum, PermissionDecision enum, keyboard shortcuts,
  and routing logic (single-file vs multi-file)
- docs/adr/ADR-044-tui-architecture-and-framework.md: Update Prompt Architecture
  item 3 from QuestionWidget to PermissionQuestionWidget with inline rendering
  description; add QuestionWidget as item 4 for non-file-specific choices

Triggered by PR #2181 (docs(tui): document PermissionQuestionWidget).
Approved via proposal issue #2178.

ISSUES CLOSED: #2178
This commit is contained in:
2026-04-03 19:03:04 +00:00
parent 77427bd7d3
commit c678fcdcc3
2 changed files with 36 additions and 2 deletions
@@ -240,7 +240,8 @@ The prompt area is docked to the bottom of the conversation and comprises:
- `` — normal prompt mode (Markdown input)
- `$` — shell mode (activated by `!` at position 0)
- `☰` — multi-line mode (activated when input contains newlines)
3. **QuestionWidget** — replaces the prompt during actor permission requests (allow/reject choices)
3. **PermissionQuestionWidget** — renders **inline in the conversation stream** for single-file permission requests. Displays the actor name, operation type, target file path, and four decision options with keyboard shortcuts (`a`/`A`/`r`/`R`). Press `v` to open the full `PermissionsScreen` for multi-file diff review. For multi-file operations, `PermissionsScreen` is pushed directly (no inline widget).
4. **QuestionWidget** — replaces the prompt during actor permission requests for non-file-specific choices (allow/reject)
4. **PersonaBar** — always visible below the prompt, showing: persona name, actor name/model, current argument preset name (from ctrl+tab cycling), scope indicator (number of scoped projects/plans), and cumulative session cost
### Theme and Styling Architecture
+34 -1
View File
@@ -29577,6 +29577,39 @@ The diff view supports three display modes, toggled with `d`:
| **Context** | Shows only changed lines with surrounding context (3 lines default) |
### Inline Permission Question Widget
For **single-file** permission requests, the TUI renders a `PermissionQuestionWidget` inline in the conversation stream rather than pushing the full `PermissionsScreen`. This avoids interrupting the conversation flow for simple allow/reject decisions.
The widget displays:
- The actor name and requested operation type
- The target file path
- Inline diff content (when available)
- Four decision options with keyboard shortcuts
| Key | Decision | Scope |
|-----|----------|-------|
| `a` | Allow once | This operation only |
| `A` | Allow always | All operations this session |
| `r` | Reject once | This operation only |
| `R` | Reject always | All operations this session |
Navigate options with `up`/`down` and confirm with `enter`, or use the single-key shortcuts directly. Press `v` to open the full `PermissionsScreen` for multi-file diff review.
**Permission request types**: `file_write`, `file_delete`, `file_read`, `shell_exec`, `network`.
**Routing logic**:
- Single-file operations → `PermissionQuestionWidget` inline in conversation stream
- Multi-file operations → `PermissionsScreen` pushed directly (no inline widget)
The widget emits a `PermissionDecisionEvent` when a decision is made, which the TUI processes to either allow or reject the pending tool operation.
**Domain models**:
- `InlinePermissionQuestion` — carries `file_path`, `request_type` (`PermissionRequestType`), `diff_content`, and `actor_name`
- `PermissionRequestType` enum: `FILE_WRITE`, `FILE_DELETE`, `FILE_READ`, `SHELL_EXEC`, `NETWORK`
- `PermissionDecision` enum: `ALLOW_ONCE`, `ALLOW_ALWAYS`, `REJECT_ONCE`, `REJECT_ALWAYS`
### Additional UI Components
@@ -43830,7 +43863,7 @@ All domain models, configuration objects, and API schemas use **Pydantic V2** (>
#### Domain Models
Every domain entity — Plan, Decision, Action, Resource, Actor, Tool, Skill, Session, Invariant, AutomationProfile, Checkpoint, CorrectionAttempt — is a Pydantic `BaseModel` subclass. Fields use Python type annotations with Pydantic field validators for business rule enforcement.
Every domain entity — Plan, Decision, Action, Resource, Actor, Tool, Skill, Session, Invariant, AutomationProfile, Checkpoint, CorrectionAttempt — is a Pydantic model subclass. Domain entities that share the canonical configuration (`str_strip_whitespace`, `validate_assignment`, `arbitrary_types_allowed=False`, `populate_by_name`, `use_enum_values`) inherit from the shared `DomainBaseModel` base class (defined in `domain/models/base.py`) rather than directly from `pydantic.BaseModel`. Classes with genuinely different configuration requirements may still subclass `BaseModel` directly. Fields use Python type annotations with Pydantic field validators for business rule enforcement.
#### Configuration Objects