Skip to content

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

Merged
A-x6 merged 2 commits into
devfrom
todos-command
Jul 31, 2026
Merged

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

Conversation

@A-x6

@A-x6A-x6 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:

consttodos=createMemo(()=>sync.data.todo[props.sessionID]??[])// ...<Showwhen={todos().length>0}fallback={<textfg={theme.textMuted}>No todos in this session yet</text>}><box><Foreach={todos()}>{(item)=><TodoItemstatus={item.status}content={item.content}/>}</For></box><textfg={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

vercelBot commented Jul 31, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
bolt-cli-appSkippedSkippedJul 31, 2026 6:13am

@coderabbitai

coderabbitaiBot 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 nameStatusExplanation
Title check✅ PassedThe title clearly identifies the new TUI /todos command and its purpose of viewing the agent task list.
Description check✅ PassedThe description includes the issue, change type, implementation details, verification results, UI note, and completed checklist.
Linked Issues check✅ PassedThe 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✅ PassedThe changes are limited to the todos dialog and session command wiring, which directly support the linked issue objectives.
Docstring Coverage✅ PassedNo 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-ioBot 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

AnalyzerStatusUpdated (UTC)Details
JavaScriptJul 31, 2026 6:13a.m.Review ↗
ShellJul 31, 2026 6:13a.m.Review ↗
SecretsJul 31, 2026 6:13a.m.Review ↗
DockerJul 31, 2026 6:13a.m.Review ↗
PythonJul 31, 2026 6:13a.m.Review ↗
CSSJul 31, 2026 6:13a.m.Review ↗
RustJul 31, 2026 6:13a.m.Review ↗
RubyJul 31, 2026 6:13a.m.Review ↗
SwiftJul 31, 2026 6:13a.m.Review ↗
PHPJul 31, 2026 6:13a.m.Review ↗
LuaJul 31, 2026 6:13a.m.Review ↗
JavaJul 31, 2026 6:13a.m.Review ↗
GoJul 31, 2026 6:13a.m.Review ↗
C & C++Jul 31, 2026 6:13a.m.Review ↗
AnsibleJul 31, 2026 6:13a.m.Review ↗
ApexJul 31, 2026 6:13a.m.Review ↗
ElixirJul 31, 2026 6:13a.m.Review ↗
GroovyJul 31, 2026 6:13a.m.Review ↗
Objective-CJul 31, 2026 6:13a.m.Review ↗
PowerShellJul 31, 2026 6:13a.m.Review ↗
TerraformJul 31, 2026 6:13a.m.Review ↗
VB.NETJul 31, 2026 6:13a.m.Review ↗
SQLJul 31, 2026 6:13a.m.Review ↗
ScalaJul 31, 2026 6:13a.m.Review ↗
PerlJul 31, 2026 6:13a.m.Review ↗
KotlinJul 31, 2026 6:13a.m.Review ↗
HelmJul 31, 2026 6:13a.m.Review ↗
ErlangJul 31, 2026 6:13a.m.Review ↗
DartJul 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.

@coderabbitaicoderabbitaiBot 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.

@A-x6
A-x6 merged commit 512e9bd into devJul 31, 2026
67 of 68 checks passed
Sign up for freeto 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

@A-x6