diff --git a/docs/adr/ADR-044-tui-architecture-and-framework.md b/docs/adr/ADR-044-tui-architecture-and-framework.md index a13d3ed46..3098b44bf 100644 --- a/docs/adr/ADR-044-tui-architecture-and-framework.md +++ b/docs/adr/ADR-044-tui-architecture-and-framework.md @@ -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 diff --git a/docs/specification.md b/docs/specification.md index 9335bd1c5..f020b553e 100644 --- a/docs/specification.md +++ b/docs/specification.md @@ -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