feat: answer approvals and send prompts from the dashboard

The dashboard stops being read-only. The selected session's tail is polled
once a second while the plain list has focus and the layout is wide, and an
unchanged tail never reaches the model, so a quiet session costs no repaint.
A row with no live buffer says so instead of polling forever.

Keys: y/n and the parsed digits answer the selected session's dialog through
`POST /api/approvals/:id/answer` (never a blind keystroke: that route
re-captures the pane and 409s when the dialog has moved on, which the TUI
reports as "no longer on screen"); `p` opens a one-line composer aimed at
the selected session; `/` searches with a 250ms debounce and Enter switches
to a live session result; `g` shows the away digest. A new prompt rings the
bell exactly once, tracked by item id so a repaint or a refetch cannot
stutter, and the plan-usage chip rides `GET /api/status` plus its telemetry
event.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-08-22 14:13:58 +02:00
parent 953a560eee
commit eb8958ddd0
3 changed files with 689 additions and 61 deletions
+7
View File
@@ -89,6 +89,12 @@ export interface TuiServerInfo {
instance: string;
/** A server answered but rejected our credentials. */
authRequired?: boolean;
/**
* Last-known plan usage, which rides `GET /api/status` rather than having a
* route of its own. Null when the account reports none (no subscription
* windows, or no statusline render yet this server process).
*/
planUsage?: TuiPlanUsage | null;
}
export interface TuiClientOptions {
@@ -482,6 +488,7 @@ export class TuiClient {
'/api/status'
);
if (status?.version) info.version = status.version;
if (status?.planUsage) info.planUsage = status.planUsage;
} catch (err) {
if (err instanceof TuiApiError && (err.status === 401 || err.status === 403)) {
info.authRequired = true;