chore(beans): triage session bugs, agent discovery bug, and TUI epic
Session list & dump epic (claudbg-tci9): - Table overflows terminal / project path truncation (claudbg-6dgc) - JSON output is array-of-arrays not array-of-objects (claudbg-pfa5) - --include help text missing valid values (claudbg-a532) - Collapse consecutive identical rows in dump (claudbg-d9ev) - Add sub-agent count column to sessions list (claudbg-xpzp) Transcription output improvements epic (claudbg-8vpb): - Tools header shows debug HashMap not readable list (claudbg-f4ot) - Duration always 0ms due to durationMs/duration_ms field mismatch (claudbg-nqxz) - Tool results hidden by default — should show with truncation (claudbg-zy1p) - Tool use input hard-capped at 120 chars ignoring --verbose (claudbg-kg0v) Agent discovery bug (claudbg-33n0): - discover_agents_for_session looks in <project>/subagents/ but actual disk structure is <project>/<session-uuid>/subagents/ TUI epic (claudbg-i6l2) + 8 child tasks: - ratatui/crossterm deps, app state, terminal/event loop, session list screen, transcript screen, sub-agents panel, quit dialog, help modal Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>main
parent
7f321060f5
commit
66c1cf5c6e
@ -0,0 +1,48 @@
|
||||
---
|
||||
# claudbg-1e1c
|
||||
title: 'TUI: quit confirmation dialog'
|
||||
status: todo
|
||||
type: task
|
||||
priority: normal
|
||||
created_at: 2026-03-30T04:47:46Z
|
||||
updated_at: 2026-03-30T04:49:03Z
|
||||
parent: claudbg-i6l2
|
||||
blocked_by:
|
||||
- claudbg-ut9q
|
||||
---
|
||||
|
||||
Implement a modal quit confirmation dialog.
|
||||
|
||||
## Trigger
|
||||
|
||||
Press `q` or `Q` from any screen (except when another modal is open).
|
||||
|
||||
## Appearance
|
||||
|
||||
```
|
||||
┌──────────────────────┐
|
||||
│ Quit claudbg? │
|
||||
│ │
|
||||
│ q = yes Esc = no │
|
||||
└──────────────────────┘
|
||||
```
|
||||
|
||||
Centered overlay on top of the current screen (using `ratatui::widgets::Clear` to clear the background area).
|
||||
|
||||
## State
|
||||
|
||||
`AppState.show_quit_dialog: bool`
|
||||
|
||||
- `q`/`Q` → `show_quit_dialog = true`
|
||||
- While dialog is shown: `q` → `should_quit = true` (exit loop), `Escape` → `show_quit_dialog = false`
|
||||
- Dialog intercepts all other key input while open.
|
||||
|
||||
## Implementation notes
|
||||
|
||||
- Use `ratatui::layout::Rect` centered calculation to position the dialog.
|
||||
- Render with `Block::bordered().title("Quit?")` and a `Paragraph` inside.
|
||||
- Use `Clear` widget behind the dialog block to prevent bleed-through.
|
||||
|
||||
## Blocked by
|
||||
|
||||
- event loop (claudbg-ut9q)
|
||||
@ -0,0 +1,55 @@
|
||||
---
|
||||
# claudbg-1tlk
|
||||
title: 'TUI: help modal listing all keyboard shortcuts'
|
||||
status: todo
|
||||
type: task
|
||||
priority: normal
|
||||
created_at: 2026-03-30T04:48:38Z
|
||||
updated_at: 2026-03-30T04:49:03Z
|
||||
parent: claudbg-i6l2
|
||||
blocked_by:
|
||||
- claudbg-ut9q
|
||||
---
|
||||
|
||||
Implement a `?` help overlay that lists all keyboard shortcuts.
|
||||
|
||||
## Trigger
|
||||
|
||||
Press `?` (or `Shift+/`) from any screen (except when another modal is open).
|
||||
|
||||
## Content
|
||||
|
||||
```
|
||||
┌─────────── Keyboard Shortcuts ────────────┐
|
||||
│ Navigation │
|
||||
│ ↑/↓ or k/j Scroll up/down │
|
||||
│ ←/→ or h/l Scroll left/right │
|
||||
│ Tab Cycle panes │
|
||||
│ Enter Open / select │
|
||||
│ Escape Go back │
|
||||
│ │
|
||||
│ Global │
|
||||
│ q / Q Quit (with confirmation) │
|
||||
│ ? Show this help │
|
||||
└───────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Press `Escape` to close.
|
||||
|
||||
## State
|
||||
|
||||
`AppState.show_help: bool`
|
||||
|
||||
- `?` → `show_help = true`
|
||||
- `Escape` → `show_help = false`
|
||||
- Help modal intercepts all key input while open.
|
||||
|
||||
## Implementation notes
|
||||
|
||||
- Same centered overlay pattern as quit dialog (Clear + Block + Paragraph).
|
||||
- Content is static — hardcoded list of shortcuts.
|
||||
- Render on top of whatever screen is active.
|
||||
|
||||
## Blocked by
|
||||
|
||||
- event loop (claudbg-ut9q)
|
||||
@ -0,0 +1,30 @@
|
||||
---
|
||||
# claudbg-6dgc
|
||||
title: Table overflows terminal — truncate long columns and respect terminal width
|
||||
status: todo
|
||||
type: bug
|
||||
priority: normal
|
||||
created_at: 2026-03-30T04:36:31Z
|
||||
updated_at: 2026-03-30T04:41:14Z
|
||||
parent: claudbg-tci9
|
||||
---
|
||||
|
||||
## Problem
|
||||
|
||||
`sessions list` table overflows the terminal width. The project path column is the main culprit — full paths like `/run/media/pop/4e1ca4f1-.../Projects/src/github.com/pop/claudbg` make rows far too wide.
|
||||
|
||||
## Current behavior
|
||||
|
||||
`src/output/table.rs` hardcodes `FALLBACK_WIDTH = 200` and applies `.max(FALLBACK_WIDTH)`, so the table is *always at least 200 chars wide* regardless of the actual terminal. No `ColumnConstraint` is applied to any column.
|
||||
|
||||
## Expected behavior
|
||||
|
||||
- The table should never exceed the actual terminal width (use `terminal_size` or `comfy_table`'s built-in terminal detection).
|
||||
- The project path column should be truncated to show the **last** N characters (tail of the path), since the trailing project name is more meaningful than the leading `/run/media/...` prefix. E.g. display `…/pop/claudbg` instead of `/run/media/pop/4e1ca4f1-…`.
|
||||
- Other columns (ID, date, model, message count) should not be truncated.
|
||||
- comfy-table supports `ColumnConstraint::MaxWidth` and `ColumnConstraint::LowerBoundary` — use these to cap the project column.
|
||||
|
||||
## Relevant files
|
||||
|
||||
- `src/output/table.rs` — `render_table`, `FALLBACK_WIDTH` constant
|
||||
- `src/commands/sessions.rs` — `list()` function that calls `render_table`
|
||||
@ -0,0 +1,34 @@
|
||||
---
|
||||
# claudbg-78xt
|
||||
title: 'TUI: add ratatui + crossterm dependencies'
|
||||
status: todo
|
||||
type: task
|
||||
created_at: 2026-03-30T04:45:06Z
|
||||
updated_at: 2026-03-30T04:45:06Z
|
||||
parent: claudbg-i6l2
|
||||
---
|
||||
|
||||
Add `ratatui` and `crossterm` to `Cargo.toml`.
|
||||
|
||||
## Changes
|
||||
|
||||
```toml
|
||||
ratatui = "0.29" # TUI framework
|
||||
crossterm = "0.28" # terminal backend (raw mode, event reading)
|
||||
```
|
||||
|
||||
Ratatui ships its own `crossterm` backend feature; use `ratatui = { version = "0.29", features = ["crossterm"] }` to pull both together.
|
||||
|
||||
## Verify
|
||||
|
||||
Run `cargo check` to confirm the dependency resolves and there are no conflicts with existing deps (`tokio`, `libsql`).
|
||||
|
||||
## Notes
|
||||
|
||||
- Do NOT add `termion` — crossterm is cross-platform and the right choice.
|
||||
- The `ratatui` crate bundles the backend integration; no need for a separate `tui-crossterm` crate.
|
||||
- Check that `ratatui 0.29` is available; if not use the latest stable.
|
||||
|
||||
## Relevant files
|
||||
|
||||
- `Cargo.toml`
|
||||
@ -0,0 +1,10 @@
|
||||
---
|
||||
# claudbg-8vpb
|
||||
title: Transcription output improvements
|
||||
status: todo
|
||||
type: epic
|
||||
created_at: 2026-03-30T04:43:30Z
|
||||
updated_at: 2026-03-30T04:43:30Z
|
||||
---
|
||||
|
||||
Groups bugs in `sessions transcribe` and `agents transcribe` output: tools display format, duration miscalculation, tool result visibility defaults, and tool input truncation.
|
||||
@ -0,0 +1,44 @@
|
||||
---
|
||||
# claudbg-9c8r
|
||||
title: 'TUI: sub-agents panel in transcript view'
|
||||
status: todo
|
||||
type: feature
|
||||
priority: normal
|
||||
created_at: 2026-03-30T04:47:15Z
|
||||
updated_at: 2026-03-30T04:49:03Z
|
||||
parent: claudbg-i6l2
|
||||
blocked_by:
|
||||
- claudbg-rudq
|
||||
---
|
||||
|
||||
Add a sub-agents panel to the right side of the transcript screen, showing all sub-agent runs for the current session.
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
┌── Transcript ──────────────────────┬─── Sub-agents ──┐
|
||||
│ [user]: … │ a8e741de agent │
|
||||
│ [assistant]: … │ > c3f920aa agent │◄ selected
|
||||
│ [tool: Bash] … │ │
|
||||
│ [tool_result]: … │ │
|
||||
└────────────────────────────────────┴──────────────────┘
|
||||
```
|
||||
|
||||
The panel is ~25% of the frame width (or a fixed ~30 chars).
|
||||
|
||||
## Implementation
|
||||
|
||||
- Use `ratatui::layout::Layout` with `Constraint::Min` for the chat area and `Constraint::Length(30)` for the panel.
|
||||
- Panel shows: short agent ID + agent type. If the session has no sub-agents, the panel can be hidden or show "No sub-agents".
|
||||
- Panel is focusable via Tab (Tab cycles: chat log → sub-agents panel → chat log).
|
||||
- When panel is focused, j/k moves selection. Enter navigates to that sub-agent's transcript (sets `screen` to `SubagentTranscript`).
|
||||
- Highlight the focused pane's border (e.g. with a colored `Block` border).
|
||||
|
||||
## Data source
|
||||
|
||||
`AppState.subagents: Vec<AgentRef>` populated via `discover_agents_for_session` when entering transcript screen.
|
||||
|
||||
## Blocked by
|
||||
|
||||
- transcript screen (claudbg-rudq)
|
||||
- agent discovery fix (claudbg-33n0)
|
||||
@ -0,0 +1,37 @@
|
||||
---
|
||||
# claudbg-a532
|
||||
title: '`--include` help text should enumerate valid values'
|
||||
status: todo
|
||||
type: bug
|
||||
priority: low
|
||||
created_at: 2026-03-30T04:38:03Z
|
||||
updated_at: 2026-03-30T04:41:14Z
|
||||
parent: claudbg-tci9
|
||||
---
|
||||
|
||||
## Problem
|
||||
|
||||
The `--include` flag help text says "Comma-separated content to include: thinking, output." but clap does not enumerate the valid tokens in `--help` output. Users cannot discover valid values from `--help` alone.
|
||||
|
||||
## Current declaration (`src/cli.rs`)
|
||||
|
||||
```rust
|
||||
/// Comma-separated content to include: thinking, output.
|
||||
#[arg(long, global = true, default_value = "")]
|
||||
pub include: IncludeList,
|
||||
```
|
||||
|
||||
The valid tokens are `thinking` and `output` (parsed in `IncludeList::from_str`).
|
||||
|
||||
## Expected behavior
|
||||
|
||||
The help output should clearly show: `[possible values: thinking, output]` or equivalent. Options:
|
||||
|
||||
1. Update the `#[arg(help = ...)]` string to explicitly state the valid values and format.
|
||||
2. Or use clap's `value_parser` with a custom validator that also shows valid choices.
|
||||
|
||||
Since `IncludeList` is a comma-separated composite (not a single enum value), option 1 (explicit help string) is simplest.
|
||||
|
||||
## Relevant files
|
||||
|
||||
- `src/cli.rs` — `IncludeList`, `GlobalOpts`, the `include` field annotation
|
||||
@ -0,0 +1,41 @@
|
||||
---
|
||||
# claudbg-i6l2
|
||||
title: 'TUI: interactive session browser'
|
||||
status: todo
|
||||
type: epic
|
||||
created_at: 2026-03-30T04:44:52Z
|
||||
updated_at: 2026-03-30T04:44:52Z
|
||||
---
|
||||
|
||||
Implement a full terminal UI using Ratatui for browsing Claude Code sessions.
|
||||
|
||||
## Design
|
||||
|
||||
**Navigation model:** drill-down (not split-pane)
|
||||
- Screen 1: full-screen session list → Enter opens transcript
|
||||
- Screen 2: full-screen transcript with embedded sub-agents panel → Tab cycles panes, Escape returns to list
|
||||
- Screen 3: sub-agent transcript (same layout as Screen 2, Escape returns to parent transcript)
|
||||
|
||||
**Session list screen**
|
||||
Columns: short ID, datetime, project (truncated tail), model, message count, sub-agent count.
|
||||
Sorted most-recent-first.
|
||||
|
||||
**Transcript screen**
|
||||
- Header: session ID, model, tokens (in/out/cache), tool call summary, duration
|
||||
- Scrollable chat log: user messages, assistant text, tool use blocks (truncated), tool results (truncated)
|
||||
- Long lines truncated with horizontal scroll
|
||||
- Sub-agents panel (Tab to focus): list of sub-agent runs for this session; Enter navigates to sub-agent transcript
|
||||
- Thinking blocks hidden by default
|
||||
|
||||
**Keyboard bindings**
|
||||
- `Up`/`Down`/`k`/`j` — navigate within pane
|
||||
- `Left`/`Right`/`h`/`l` — horizontal scroll in transcript
|
||||
- `Tab` — cycle focus between panes
|
||||
- `Enter` — drill into selection
|
||||
- `Escape` — go back
|
||||
- `q`/`Q` — quit confirmation dialog (q=confirm, Esc=cancel)
|
||||
- `?` — help modal listing all shortcuts (Esc to close)
|
||||
|
||||
**Non-goals for this milestone**
|
||||
- Live refresh / follow mode (future feature)
|
||||
- Color themes / configuration
|
||||
@ -0,0 +1,10 @@
|
||||
---
|
||||
# claudbg-kxii
|
||||
title: 'TUI: interactive session browser'
|
||||
status: todo
|
||||
type: epic
|
||||
created_at: 2026-03-30T04:34:21Z
|
||||
updated_at: 2026-03-30T04:34:21Z
|
||||
---
|
||||
|
||||
Implement a full terminal UI for claudbg using ratatui + crossterm. The TUI provides drill-down navigation: a full-screen session list, a transcript view with a sub-agents side panel, and nested sub-agent transcript views. Data is loaded once on screen entry (no live refresh in this iteration). Navigation is keyboard-driven (vim-style + arrow keys). Modals for quit confirmation and a help screen are included.
|
||||
@ -0,0 +1,56 @@
|
||||
---
|
||||
# claudbg-nq36
|
||||
title: 'TUI: app state model and screen enum'
|
||||
status: todo
|
||||
type: task
|
||||
priority: normal
|
||||
created_at: 2026-03-30T04:45:19Z
|
||||
updated_at: 2026-03-30T04:49:03Z
|
||||
parent: claudbg-i6l2
|
||||
blocked_by:
|
||||
- claudbg-78xt
|
||||
---
|
||||
|
||||
Define the central `AppState` struct and `Screen` enum that drive the entire TUI.
|
||||
|
||||
## Types to define (`src/tui/state.rs` or `src/commands/tui/state.rs`)
|
||||
|
||||
```rust
|
||||
pub enum Screen {
|
||||
SessionList,
|
||||
Transcript { session_id: String },
|
||||
SubagentTranscript { parent_session_id: String, agent_id: String },
|
||||
}
|
||||
|
||||
pub enum Focus {
|
||||
ChatLog,
|
||||
SubagentsPanel,
|
||||
}
|
||||
|
||||
pub struct AppState {
|
||||
pub screen: Screen,
|
||||
// Session list
|
||||
pub sessions: Vec<SessionListItem>, // loaded once
|
||||
pub list_selected: usize,
|
||||
// Transcript
|
||||
pub transcript_entries: Vec<RawEntry>,
|
||||
pub transcript_scroll: usize, // vertical scroll offset
|
||||
pub transcript_h_scroll: usize, // horizontal scroll offset
|
||||
pub subagents: Vec<AgentRef>,
|
||||
pub subagent_selected: usize,
|
||||
pub focus: Focus,
|
||||
// Modals
|
||||
pub show_quit_dialog: bool,
|
||||
pub show_help: bool,
|
||||
}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `SessionListItem` is a lightweight struct with the display fields (short_id, date, project, model, msg_count, agent_count).
|
||||
- State transitions: `AppState::enter_transcript(session_id)` loads entries + subagents. `AppState::go_back()` pops the screen stack (or just switches back to `SessionList`).
|
||||
- Keep all data loading in state transitions so the render function is pure.
|
||||
|
||||
## Blocked by
|
||||
|
||||
- ratatui dependency task (claudbg-78xt)
|
||||
@ -0,0 +1,51 @@
|
||||
---
|
||||
# claudbg-nqxz
|
||||
title: Duration shows 0ms — RawEntry.duration_ms field name mismatch (durationMs vs duration_ms)
|
||||
status: todo
|
||||
type: bug
|
||||
priority: high
|
||||
created_at: 2026-03-30T04:44:06Z
|
||||
updated_at: 2026-03-30T04:44:06Z
|
||||
parent: claudbg-8vpb
|
||||
---
|
||||
|
||||
## Problem
|
||||
|
||||
`sessions transcribe` shows `Duration: 0ms` even for long sessions.
|
||||
|
||||
## Root cause
|
||||
|
||||
The JSONL file uses camelCase `durationMs` at the entry level:
|
||||
|
||||
```json
|
||||
{"type": "system", "durationMs": 3446227, ...}
|
||||
```
|
||||
|
||||
But `RawEntry` declares the field as `duration_ms: Option<u64>` with no serde rename:
|
||||
|
||||
```rust
|
||||
// src/models/session.rs:33
|
||||
pub duration_ms: Option<u64>,
|
||||
```
|
||||
|
||||
Serde looks for `duration_ms` (snake_case), finds nothing, and the value falls into the `extra` catch-all map instead. `compute_stats` then sums zeros.
|
||||
|
||||
## Fix
|
||||
|
||||
Add `#[serde(rename = "durationMs")]` to the field:
|
||||
|
||||
```rust
|
||||
#[serde(rename = "durationMs")]
|
||||
pub duration_ms: Option<u64>,
|
||||
```
|
||||
|
||||
Alternatively use `#[serde(alias = "durationMs")]` to accept both forms.
|
||||
|
||||
## Confirmed by
|
||||
|
||||
Running against session `21fae0a8`: `grep '"durationMs":[0-9]'` finds entries like `{"type":"system","durationMs":3446227,...}` confirming the field name is camelCase.
|
||||
|
||||
## Relevant files
|
||||
|
||||
- `src/models/session.rs` — `RawEntry`, `duration_ms` field (line 33)
|
||||
- `src/models/stats.rs` — `compute_stats`, accumulates `entry.duration_ms`
|
||||
@ -0,0 +1,40 @@
|
||||
---
|
||||
# claudbg-pfa5
|
||||
title: JSON output is array-of-arrays instead of array-of-objects
|
||||
status: todo
|
||||
type: bug
|
||||
priority: normal
|
||||
created_at: 2026-03-30T04:37:05Z
|
||||
updated_at: 2026-03-30T04:41:14Z
|
||||
parent: claudbg-tci9
|
||||
---
|
||||
|
||||
## Problem
|
||||
|
||||
`sessions list --output json` and `sessions dump --output json` serialize rows as `Vec<Vec<String>>`, producing an array of arrays with no field names:
|
||||
|
||||
```json
|
||||
[["21fae0a8", "2024-01-01", "/path", "claude-3", "42"], ...]
|
||||
```
|
||||
|
||||
## Expected behavior
|
||||
|
||||
Output should be an array of objects with named keys:
|
||||
|
||||
```json
|
||||
[{"id": "21fae0a8", "date": "2024-01-01", "project": "/path", "model": "claude-3", "messages": 42, "subagents": 0}, ...]
|
||||
```
|
||||
|
||||
## Affected commands
|
||||
|
||||
- `sessions list --output json`: keys should be `id`, `date`, `project`, `model`, `messages`, `subagents`
|
||||
- `sessions dump --output json`: keys should be `seq`, `timestamp`, `type`, `role`, `content`
|
||||
|
||||
## Root cause
|
||||
|
||||
`src/commands/sessions.rs` passes `&rows: &Vec<Vec<String>>` directly to `render_json`. The fix is to build a typed struct or `serde_json::Value` map per row before serializing.
|
||||
|
||||
## Relevant files
|
||||
|
||||
- `src/commands/sessions.rs` — `list()` and `dump()` JSON output branches
|
||||
- `src/output/json.rs` — generic `render_json`
|
||||
@ -0,0 +1,40 @@
|
||||
---
|
||||
# claudbg-pta8
|
||||
title: 'TUI: session list screen widget'
|
||||
status: todo
|
||||
type: feature
|
||||
priority: normal
|
||||
created_at: 2026-03-30T04:45:53Z
|
||||
updated_at: 2026-03-30T04:49:03Z
|
||||
parent: claudbg-i6l2
|
||||
blocked_by:
|
||||
- claudbg-nq36
|
||||
---
|
||||
|
||||
Render the full-screen session list as the TUI's home screen.
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
┌─ Sessions ──────────────────────────────────────────────────────┐
|
||||
│ ID Date Project Model Msgs Agents │
|
||||
│ ────────────────────────────────────────────────────────────────────── │
|
||||
│ 21fae0a8 2026-03-29 14:32:01 …/pop/claudbg claude-3 42 3 │◄ selected (highlighted)
|
||||
│ def4776b 2026-03-28 10:15:44 …/pop/claudbg claude-3 128 1 │
|
||||
│ ... │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
- Use `ratatui::widgets::Table` with `TableState` for selection tracking.
|
||||
- Highlight the selected row with a `Style` that inverts colors or uses a distinct background.
|
||||
- Columns: ID (8), Date (20), Project (dynamic, truncated to tail), Model (20), Msgs (6), Agents (7).
|
||||
- Project path: display only the last 30 or so characters (prefix with `…`).
|
||||
- Populate from `AppState.sessions` (loaded on TUI start from `discover_sessions` + DB).
|
||||
- Scroll with arrow keys / j/k; selected index tracked in `AppState.list_selected`.
|
||||
|
||||
## Blocked by
|
||||
|
||||
- app state model (claudbg-nq36)
|
||||
- agent discovery fix (claudbg-33n0) — for accurate agent counts
|
||||
@ -0,0 +1,10 @@
|
||||
---
|
||||
# claudbg-tci9
|
||||
title: Session list & dump improvements
|
||||
status: todo
|
||||
type: epic
|
||||
created_at: 2026-03-30T04:34:16Z
|
||||
updated_at: 2026-03-30T04:34:16Z
|
||||
---
|
||||
|
||||
Groups bugs and improvements to the `sessions list` and `sessions dump` commands: table overflow, JSON output format, --include help text, duplicate row collapsing, and sub-agent count.
|
||||
@ -0,0 +1,38 @@
|
||||
---
|
||||
# claudbg-ut9q
|
||||
title: 'TUI: terminal setup, event loop, and teardown'
|
||||
status: todo
|
||||
type: task
|
||||
priority: normal
|
||||
created_at: 2026-03-30T04:45:32Z
|
||||
updated_at: 2026-03-30T04:49:03Z
|
||||
parent: claudbg-i6l2
|
||||
blocked_by:
|
||||
- claudbg-nq36
|
||||
---
|
||||
|
||||
Implement terminal initialization, the main event loop, and graceful teardown.
|
||||
|
||||
## Responsibilities
|
||||
|
||||
1. **Setup:** enable raw mode (`crossterm::terminal::enable_raw_mode`), switch to alternate screen (`EnterAlternateScreen`), create `CrosstermBackend`, instantiate `ratatui::Terminal`.
|
||||
|
||||
2. **Panic hook:** install a panic hook that restores the terminal before printing the panic message (prevents garbled terminal on crash).
|
||||
|
||||
3. **Event loop:** `loop { terminal.draw(|f| render(f, &state)); if event::poll(Duration::from_millis(50))? { handle_event(event::read()?, &mut state); } if state.should_quit { break; } }`
|
||||
|
||||
4. **Teardown:** disable raw mode, leave alternate screen.
|
||||
|
||||
## Entry point
|
||||
|
||||
Replaces the stub in `src/commands/stubs.rs` (the `Tui` command handler). The `tui()` async function should call into a synchronous `run_tui()` function since ratatui is sync.
|
||||
|
||||
## Notes
|
||||
|
||||
- Use `crossterm::event::Event` for keyboard input — no mouse needed for this milestone.
|
||||
- The 50 ms poll timeout gives ~20 fps without busy-spinning.
|
||||
- Teardown must run even on error: use a RAII guard or wrap in a closure.
|
||||
|
||||
## Blocked by
|
||||
|
||||
- ratatui deps (claudbg-78xt), app state (claudbg-nq36)
|
||||
@ -0,0 +1,42 @@
|
||||
---
|
||||
# claudbg-xpzp
|
||||
title: '`sessions list` should show sub-agent run count per session'
|
||||
status: todo
|
||||
type: bug
|
||||
priority: normal
|
||||
created_at: 2026-03-30T04:40:53Z
|
||||
updated_at: 2026-03-30T04:43:26Z
|
||||
parent: claudbg-tci9
|
||||
blocked_by:
|
||||
- claudbg-33n0
|
||||
---
|
||||
|
||||
## Problem
|
||||
|
||||
`sessions list` has no column showing how many sub-agent runs a session spawned, making it impossible to identify sessions that used the Agent tool.
|
||||
|
||||
## Expected behavior
|
||||
|
||||
Add a `Sub-agents` column to `sessions list` showing the count of sub-agent JSONL files associated with each session. Zero for sessions with no sub-agents.
|
||||
|
||||
## Disk structure (important)
|
||||
|
||||
The actual subagent files live at:
|
||||
```
|
||||
~/.claude/projects/<project-dir>/<session-uuid>/subagents/agent-<id>.jsonl
|
||||
```
|
||||
Note: there is a *directory* named `<session-uuid>` (without `.jsonl`) alongside the session file that contains the `subagents/` folder.
|
||||
|
||||
The existing `discover_agents_for_session(session_file)` function currently looks in the *wrong place* (see separate bug). Once that is fixed, the agent count can be obtained by calling `discover_agents_for_session` for each session and taking `.len()`.
|
||||
|
||||
## Implementation notes
|
||||
|
||||
- In `sessions list`, after syncing sessions, call `discover_agents_for_session(&session_ref.file_path)` for each session to get the count.
|
||||
- Add the count as the last column in the table row.
|
||||
- Update JSON output to include `subagents` field.
|
||||
- This is blocked on the subagent path discovery bug being fixed first.
|
||||
|
||||
## Relevant files
|
||||
|
||||
- `src/commands/sessions.rs` — `list()` function
|
||||
- `src/parser/discovery.rs` — `discover_agents_for_session`
|
||||
Loading…
Reference in New Issue