Notification center modal for pending actionable notices.
Surfaces a list of PendingNotification entries as single-line rows.
Selecting a row drills into a dedicated detail modal
(UpdateAvailableScreen for update entries, NotificationDetailScreen
otherwise) stacked on top of the center. When the detail modal
dismisses with a terminal action (one that closes the center) the
center dismisses with a NotificationActionResult so the app layer can
dispatch. Actions that must keep the center open are handled in place:
SUPPRESS via
NotificationSuppressRequested (so the remaining notifications stay
reachable) and actions in IN_PLACE_ACTIONS via
NotificationActionRequested (so a follow-up modal, e.g. the API-key
prompt, stacks on top and Esc returns to the center). When the detail
cancels, the center stays open on the list.
Actions handled in place without dismissing the center.
Each opens a follow-up modal on top of the center, so the center stays
mounted and Esc in that modal returns here (rationale in
NotificationActionRequested). SUPPRESS is also handled in place but
routes through its own NotificationSuppressRequested message, so it is
deliberately excluded from this set.
Get the glyph set for the current charset mode.
Check whether the terminal is in ASCII charset mode.
Convenience wrapper so widgets can branch on charset without importing
both _detect_charset_mode and CharsetMode.
A single notice waiting for user action.
Immutable value object: the registry owns the
key-to-toast-identity binding (see NotificationRegistry) so
external callers cannot corrupt click-routing indices by mutating
notifications after construction.
Stable identifiers for notification actions dispatched by the app.
Typed payload for an update-available notification.
Dismissal payload identifying which action the user picked.
The screen returns this via dismiss() when the user drills into
a notification and selects an action; it returns None when the
user cancels with Esc without committing to an action.
Posted when a notification row is clicked with the mouse.
Posted when the user picks SUPPRESS from a notification's detail modal.
The center does not dismiss on SUPPRESS because the remaining
notifications should still be reachable in place. The app handles
this message by running the suppress dispatch and calling
NotificationCenterScreen.reload with the refreshed registry
snapshot.
Posted for an action that opens a follow-up modal in place.
Some actions (those in IN_PLACE_ACTIONS, currently ENTER_API_KEY)
push another modal, such as the API-key prompt, on top of the
still-open center. Dismissing the center first would drop that stack,
so Esc in the follow-up modal would fall through to the base screen
instead of returning here. The app handles this message by dispatching
the action while the center stays mounted, then reloading it with the
refreshed registry snapshot.
Modal listing pending notifications with drill-in details.
Each PendingNotification is a single row. Up/Down (or j/k)
moves the cursor; Enter or click pushes a detail modal for the
highlighted entry. The detail modal carries the action list and
dismisses with an ActionId or None. Esc on the center returns
None.
LangChain brand colors and semantic constants for the app.
Single source of truth for color values used in Python code (Rich markup,
Content.styled, Content.from_markup). CSS-side styling should reference
Textual CSS variables: built-in variables
($primary, $background, $text-muted, $error-muted, etc.) are set via
register_theme() in DeepAgentsApp.__init__, while the few app-specific
variables ($mode-bash, $mode-command, $mode-incognito, $skill,
$skill-hover, $tool, $tool-hover) are backed by these constants via
App.get_theme_variable_defaults().
Code that needs custom CSS variable values should call
get_css_variable_defaults(dark=...). For the full semantic color palette, look
up the ThemeColors instance via get_registry().
Users can define custom themes in ~/.deepagents/config.toml under
[themes.<name>] sections. Each new theme section must include label (str);
dark (bool) defaults to False if omitted (set to True for dark themes).
Color fields are optional and fall back to the built-in dark/light palette based
on the dark flag. Sections whose name matches a built-in theme override its
colors without replacing it. See _load_user_themes() for details.