Skip to content

feat(tui): /todos command to view the agent task list - #72

Merged
DevFlex-AI merged 2 commits into
devfrom
todos-command
Jul 31, 2026
Merged

feat(tui): /todos command to view the agent task list#72
DevFlex-AI merged 2 commits into
devfrom
todos-command

Conversation

@DevFlex-AI

@DevFlex-AI DevFlex-AI commented Jul 31, 2026

Copy link
Copy Markdown

Issue for this PR

Closes #70

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Adds /todos (alias /todo) to the TUI: a dialog showing the agent's live task list for the current session. Everything below the dialog already existed (the todowrite tool, the todo table, the todo.updated SSE event, and the sync store's todo map), so the dialog is a pure read of reactive state and updates in place while the agent works, no polling:

const todos = createMemo(() => sync.data.todo[props.sessionID] ?? [])
// ...
<Show when={todos().length > 0} fallback={<text fg={theme.textMuted}>No todos in this session yet</text>}>
  <box>
    <For each={todos()}>{(item) => <TodoItem status={item.status} content={item.content} />}</For>
  </box>
  <text fg={theme.textMuted}>{done()}/{todos().length} completed</text>
</Show>

Unlike the existing sidebar todo panel, which hides itself once every item is completed and needs a wide terminal (or the overlay toggle), the dialog shows the full list including completed items and works at any width. Rows reuse the existing TodoItem component so styling stays consistent with the sidebar and transcript renderings.

How did you verify your code works?

  • bunx tsgo --noEmit in packages/tui: clean
  • bun test in packages/tui: 198 pass

Screenshots / recordings

N/A (dialog reuses the existing TodoItem rows; no new visual language)

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

View with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is enabled.

Summary by CodeRabbit

  • New Features
    • Added a live todo list dialog for sessions, showing completed items and progress counts.
    • Added /todos and /todo commands to open the todo list for the current session.
    • Added an empty state and escape control for easier navigation.

@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
bolt-cli-app Skipped Skipped Jul 31, 2026 6:13am

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a DialogTodos component that displays synchronized session todos, including completed items and counts. Adds /todos and /todo session commands to open the dialog for the active session.

Changes

Session todo viewing

Layer / File(s) Summary
Todo dialog rendering
packages/tui/src/component/dialog-todos.tsx
Adds DialogTodos with synchronized todo data, completion counts, empty-state rendering, and escape dismissal.
Session todo command
packages/tui/src/routes/session/index.tsx
Adds the View todos command with /todos and /todo aliases. The command opens DialogTodos for the active session.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SessionCommand
  participant DialogTodos
  participant SyncStore
  User->>SessionCommand: Execute /todos or /todo
  SessionCommand->>DialogTodos: Open for active session
  DialogTodos->>SyncStore: Read session todos
  SyncStore-->>DialogTodos: Return todos including completed items
  DialogTodos-->>User: Render todo list and completion count
Loading

Suggested reviewers: rekram1-node, simonklee

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the new TUI /todos command and its purpose of viewing the agent task list.
Description check ✅ Passed The description includes the issue, change type, implementation details, verification results, UI note, and completed checklist.
Linked Issues check ✅ Passed The changes implement issue #70 by adding /todos and /todo, showing all session tasks reactively, including completed items, in a dialog suitable for narrow terminals.
Out of Scope Changes check ✅ Passed The changes are limited to the todos dialog and session command wiring, which directly support the linked issue objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch todos-command

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

The following comment was made by an LLM, it may be inaccurate:

@deepsource-io

deepsource-io Bot commented Jul 31, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in ba2adba...a6ee57e on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade  

Focus Area: Reliability
Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
JavaScript Jul 31, 2026 6:13a.m. Review ↗
Shell Jul 31, 2026 6:13a.m. Review ↗
Secrets Jul 31, 2026 6:13a.m. Review ↗
Docker Jul 31, 2026 6:13a.m. Review ↗
Python Jul 31, 2026 6:13a.m. Review ↗
CSS Jul 31, 2026 6:13a.m. Review ↗
Rust Jul 31, 2026 6:13a.m. Review ↗
Ruby Jul 31, 2026 6:13a.m. Review ↗
Swift Jul 31, 2026 6:13a.m. Review ↗
PHP Jul 31, 2026 6:13a.m. Review ↗
Lua Jul 31, 2026 6:13a.m. Review ↗
Java Jul 31, 2026 6:13a.m. Review ↗
Go Jul 31, 2026 6:13a.m. Review ↗
C & C++ Jul 31, 2026 6:13a.m. Review ↗
Ansible Jul 31, 2026 6:13a.m. Review ↗
Apex Jul 31, 2026 6:13a.m. Review ↗
Elixir Jul 31, 2026 6:13a.m. Review ↗
Groovy Jul 31, 2026 6:13a.m. Review ↗
Objective-C Jul 31, 2026 6:13a.m. Review ↗
PowerShell Jul 31, 2026 6:13a.m. Review ↗
Terraform Jul 31, 2026 6:13a.m. Review ↗
VB.NET Jul 31, 2026 6:13a.m. Review ↗
SQL Jul 31, 2026 6:13a.m. Review ↗
Scala Jul 31, 2026 6:13a.m. Review ↗
Perl Jul 31, 2026 6:13a.m. Review ↗
Kotlin Jul 31, 2026 6:13a.m. Review ↗
Helm Jul 31, 2026 6:13a.m. Review ↗
Erlang Jul 31, 2026 6:13a.m. Review ↗
Dart Jul 31, 2026 6:13a.m. Review ↗
C# Jul 31, 2026 6:13a.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/tui/src/component/dialog-todos.tsx (1)

18-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use the theme context through dot notation.

Line 18 destructures theme from the theme context. Keep the context object and access themeContext.theme to preserve object context.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/tui/src/component/dialog-todos.tsx` at line 18, Update the theme
access in the component to retain the object returned by useTheme, then read the
value through themeContext.theme instead of destructuring theme. Preserve the
existing theme usage behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/tui/src/component/dialog-todos.tsx`:
- Line 18: Update the theme access in the component to retain the object
returned by useTheme, then read the value through themeContext.theme instead of
destructuring theme. Preserve the existing theme usage behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 50bb9016-2849-4864-a327-70ab441bdb29

📥 Commits

Reviewing files that changed from the base of the PR and between ba2adba and a6ee57e.

📒 Files selected for processing (2)
  • packages/tui/src/component/dialog-todos.tsx
  • packages/tui/src/routes/session/index.tsx

Comment on lines +16 to +43
export function DialogTodos(props: DialogTodosProps) {
const sync = useSync()
const { theme } = useTheme()
const dialog = useDialog()
const todos = createMemo(() => sync.data.todo[props.sessionID] ?? [])
const done = createMemo(() => todos().filter((item) => item.status === "completed").length)

return (
<box paddingLeft={2} paddingRight={2} gap={1} paddingBottom={1}>
<box flexDirection="row" justifyContent="space-between">
<text fg={theme.text} attributes={TextAttributes.BOLD}>
Todos
</text>
<text fg={theme.textMuted} onMouseUp={() => dialog.clear()}>
esc
</text>
</box>
<Show when={todos().length > 0} fallback={<text fg={theme.textMuted}>No todos in this session yet</text>}>
<box>
<For each={todos()}>{(item) => <TodoItem status={item.status} content={item.content} />}</For>
</box>
<text fg={theme.textMuted}>
{done()}/{todos().length} completed
</text>
</Show>
</box>
)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable


It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an ES module export at module scope, not a global-scope declaration; it matches the export pattern of every other dialog component in the TUI package.

const done = createMemo(() => todos().filter((item) => item.status === "completed").length)

return (
<box paddingLeft={2} paddingRight={2} gap={1} paddingBottom={1}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown property 'paddingLeft' found


React components use JSX, not HTML.
So we need to use JSX attributes and React replicate the respective HTML property/attribute while rendering.
Use of HTML property in JSX can sometimes lead to errors.
For example, class is a keyword in JavaScript (JSX is an extension of JavaScript), so it will throw an error.
However, in HTML it is a valid attribute.

Note: If you use React with Web Components, use the class attribute instead.

const done = createMemo(() => todos().filter((item) => item.status === "completed").length)

return (
<box paddingLeft={2} paddingRight={2} gap={1} paddingBottom={1}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown property 'paddingRight' found


React components use JSX, not HTML.
So we need to use JSX attributes and React replicate the respective HTML property/attribute while rendering.
Use of HTML property in JSX can sometimes lead to errors.
For example, class is a keyword in JavaScript (JSX is an extension of JavaScript), so it will throw an error.
However, in HTML it is a valid attribute.

Note: If you use React with Web Components, use the class attribute instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False positive: this is a SolidJS component using @OpenTui's terminal renderer, where paddingRight is a valid prop on the box intrinsic element; React DOM rules do not apply.

const done = createMemo(() => todos().filter((item) => item.status === "completed").length)

return (
<box paddingLeft={2} paddingRight={2} gap={1} paddingBottom={1}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown property 'gap' found


React components use JSX, not HTML.
So we need to use JSX attributes and React replicate the respective HTML property/attribute while rendering.
Use of HTML property in JSX can sometimes lead to errors.
For example, class is a keyword in JavaScript (JSX is an extension of JavaScript), so it will throw an error.
However, in HTML it is a valid attribute.

Note: If you use React with Web Components, use the class attribute instead.

const done = createMemo(() => todos().filter((item) => item.status === "completed").length)

return (
<box paddingLeft={2} paddingRight={2} gap={1} paddingBottom={1}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown property 'paddingBottom' found


React components use JSX, not HTML.
So we need to use JSX attributes and React replicate the respective HTML property/attribute while rendering.
Use of HTML property in JSX can sometimes lead to errors.
For example, class is a keyword in JavaScript (JSX is an extension of JavaScript), so it will throw an error.
However, in HTML it is a valid attribute.

Note: If you use React with Web Components, use the class attribute instead.

return (
<box paddingLeft={2} paddingRight={2} gap={1} paddingBottom={1}>
<box flexDirection="row" justifyContent="space-between">
<text fg={theme.text} attributes={TextAttributes.BOLD}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown property 'fg' found


React components use JSX, not HTML.
So we need to use JSX attributes and React replicate the respective HTML property/attribute while rendering.
Use of HTML property in JSX can sometimes lead to errors.
For example, class is a keyword in JavaScript (JSX is an extension of JavaScript), so it will throw an error.
However, in HTML it is a valid attribute.

Note: If you use React with Web Components, use the class attribute instead.

return (
<box paddingLeft={2} paddingRight={2} gap={1} paddingBottom={1}>
<box flexDirection="row" justifyContent="space-between">
<text fg={theme.text} attributes={TextAttributes.BOLD}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown property 'attributes' found


React components use JSX, not HTML.
So we need to use JSX attributes and React replicate the respective HTML property/attribute while rendering.
Use of HTML property in JSX can sometimes lead to errors.
For example, class is a keyword in JavaScript (JSX is an extension of JavaScript), so it will throw an error.
However, in HTML it is a valid attribute.

Note: If you use React with Web Components, use the class attribute instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False positive: attributes is a valid @OpenTui text prop (TextAttributes flags) in this SolidJS TUI renderer; React DOM attribute rules do not apply.

<text fg={theme.text} attributes={TextAttributes.BOLD}>
Todos
</text>
<text fg={theme.textMuted} onMouseUp={() => dialog.clear()}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown property 'fg' found


React components use JSX, not HTML.
So we need to use JSX attributes and React replicate the respective HTML property/attribute while rendering.
Use of HTML property in JSX can sometimes lead to errors.
For example, class is a keyword in JavaScript (JSX is an extension of JavaScript), so it will throw an error.
However, in HTML it is a valid attribute.

Note: If you use React with Web Components, use the class attribute instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False positive: fg is a valid @OpenTui text prop for foreground color in this SolidJS TUI renderer; React DOM attribute rules do not apply.

esc
</text>
</box>
<Show when={todos().length > 0} fallback={<text fg={theme.textMuted}>No todos in this session yet</text>}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown property 'fg' found


React components use JSX, not HTML.
So we need to use JSX attributes and React replicate the respective HTML property/attribute while rendering.
Use of HTML property in JSX can sometimes lead to errors.
For example, class is a keyword in JavaScript (JSX is an extension of JavaScript), so it will throw an error.
However, in HTML it is a valid attribute.

Note: If you use React with Web Components, use the class attribute instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False positive: fg is a valid @OpenTui text prop for foreground color in this SolidJS TUI renderer; React DOM attribute rules do not apply.

<box>
<For each={todos()}>{(item) => <TodoItem status={item.status} content={item.content} />}</For>
</box>
<text fg={theme.textMuted}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown property 'fg' found


React components use JSX, not HTML.
So we need to use JSX attributes and React replicate the respective HTML property/attribute while rendering.
Use of HTML property in JSX can sometimes lead to errors.
For example, class is a keyword in JavaScript (JSX is an extension of JavaScript), so it will throw an error.
However, in HTML it is a valid attribute.

Note: If you use React with Web Components, use the class attribute instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False positive: fg is a valid @OpenTui text prop for foreground color in this SolidJS TUI renderer; React DOM attribute rules do not apply.

@DevFlex-AI
DevFlex-AI merged commit 512e9bd into dev Jul 31, 2026
67 of 68 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: /todos command to view the agent task list

1 participant