Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
2f83f93
refactor(tui): extract shared list and layout state
EngineerProjects Jun 4, 2026
2c23e4e
refactor(tui): reorganize into app common components
EngineerProjects Jun 4, 2026
e8aa3d3
refactor(tui): move ansi helper into common
EngineerProjects Jun 4, 2026
96936ec
feat(tui): add richer tool rendering and details pane
EngineerProjects Jun 5, 2026
d9a49db
feat(tui): align composer and tool summaries
EngineerProjects Jun 5, 2026
9eed56f
fix(tui): simplify composer visuals
EngineerProjects Jun 5, 2026
ca323a2
feat(tui): polish header bar
EngineerProjects Jun 5, 2026
d9d8916
docs(tui): note roadmap and clean welcome wordmark
EngineerProjects Jun 5, 2026
a4ea177
merge: integrate TUI overhaul into dev
EngineerProjects Jun 5, 2026
d545f58
fix(tui): satisfy staticcheck for tool rendering
EngineerProjects Jun 5, 2026
1147e01
feat(tui): add status lane and simplify footer
EngineerProjects Jun 5, 2026
0598596
feat(tui): polish primary chat rendering
EngineerProjects Jun 5, 2026
d63ff2d
feat(tui): add mouse copy interactions
EngineerProjects Jun 5, 2026
c3263f1
feat(tui): highlight mouse text selection
EngineerProjects Jun 5, 2026
6076748
feat(tui): make thinking blocks clickable
EngineerProjects Jun 5, 2026
ddc9117
fix(tui): warm selection highlight tone
EngineerProjects Jun 5, 2026
34abca6
feat(tui): add explicit tool click zones
EngineerProjects Jun 5, 2026
70a09cc
fix(tui): restore inline user messages
EngineerProjects Jun 5, 2026
9a02338
feat(tui): persist colored mouse selection
EngineerProjects Jun 5, 2026
91473c8
fix(tui): preserve full colored selections
EngineerProjects Jun 5, 2026
a893c29
feat(tui): add word and line mouse selection
EngineerProjects Jun 5, 2026
cd6213a
feat(tui): reorganize commands and skill slash input
EngineerProjects Jun 5, 2026
f51304b
fix(tui): restore visible input cursor
EngineerProjects Jun 5, 2026
8ea9c7c
feat(tui): add selection copy shortcuts
EngineerProjects Jun 5, 2026
c0372bd
fix(tui): report clipboard availability accurately
EngineerProjects Jun 5, 2026
1199af8
docs(tui): note clipboard backends and clean copied text
EngineerProjects Jun 5, 2026
d8599cb
feat(tui): turn ctrl+p into settings hub
EngineerProjects Jun 5, 2026
83d38f2
refactor(tui): simplify settings commands
EngineerProjects Jun 5, 2026
47e4443
feat(tui): load live settings sections
EngineerProjects Jun 5, 2026
9957ee5
fix(tui): constrain settings panel viewport
EngineerProjects Jun 5, 2026
67be940
feat(tui): insert skills from settings
EngineerProjects Jun 5, 2026
d363881
feat(tui): add slash skill suggestions
EngineerProjects Jun 5, 2026
69f349d
refactor(tui): tighten slash skill autocomplete
EngineerProjects Jun 5, 2026
51c9021
fix(tui): align slash popup with composer
EngineerProjects Jun 5, 2026
488b986
docs(tui): refresh captures and fix lint
EngineerProjects Jun 5, 2026
25c9b06
Merge pull request #31 from EngineerProjects/refactor/tui-overhaul-dev
EngineerProjects Jun 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
<br><sub><b>Welcome</b> — up and running in 10 seconds</sub>
</td>
<td align="center" width="50%">
<img src="docs/captures/commands_pannel.png" alt="Commands palette" width="100%">
<br><sub><b>Commands palette</b> — every shortcut, one keystroke away (<code>ctrl+p</code>)</sub>
<img src="docs/captures/commands_pannel.png" alt="Settings panel" width="100%">
<br><sub><b>Settings panel</b> — every shortcut, one keystroke away (<code>ctrl+p</code>)</sub>
</td>
</tr>
<tr>
Expand All @@ -56,7 +56,11 @@
</tr>
</table>

> **Keyboard shortcuts:** `ctrl+p` commands · `ctrl+m` model · `ctrl+s` sessions · `ctrl+,` provider config · `ctrl+e` select mode · `ctrl+c` cancel/quit
> **Keyboard shortcuts:** `ctrl+p` settings · `ctrl+m` model · `ctrl+s` sessions · `ctrl+,` provider config · `ctrl+shift+c` copy selection · `ctrl+c` cancel/quit

> **Clipboard note (Linux):** selection copy works best when `wl-clipboard` (Wayland) or `xclip`/`xsel` (X11) is installed. Without a system clipboard backend, Nexus can request terminal clipboard access but cannot guarantee a real system copy.

> **Compaction note:** transcript compaction is automatic today. A dedicated manual compact action is planned for the TUI once the runtime exposes a real manual-compaction hook.

---

Expand Down
79 changes: 77 additions & 2 deletions cmd/cli/tui.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"os"
"path/filepath"
"sort"
"strings"
"sync"
"sync/atomic"
Expand All @@ -15,9 +16,10 @@ import (
"github.com/EngineerProjects/nexus-engine/internal/monitoring"
"github.com/EngineerProjects/nexus-engine/internal/providers"
"github.com/EngineerProjects/nexus-engine/internal/tui"
tuimodel "github.com/EngineerProjects/nexus-engine/internal/tui/model"
tuiapp "github.com/EngineerProjects/nexus-engine/internal/tui/app"
engineconfig "github.com/EngineerProjects/nexus-engine/pkg/config"
"github.com/EngineerProjects/nexus-engine/pkg/sdk"
skillspkg "github.com/EngineerProjects/nexus-engine/pkg/skills"
)

// chunkDebounce batches streaming text chunks at 33ms intervals (crush pattern).
Expand Down Expand Up @@ -351,6 +353,78 @@ func (w *nexusWorkspace) DeleteProviderField(ctx context.Context, providerID, fi
return database.DeleteCredential(ctx, providerCredKey(fieldKey, providerID))
}

func (w *nexusWorkspace) LoadToolCatalog(ctx context.Context) []tui.ToolInfo {
surface, err := w.client.BuildToolSurface(ctx)
if err != nil || surface == nil {
return nil
}
items := make([]tui.ToolInfo, 0, len(surface.Tools))
for _, tool := range surface.Tools {
items = append(items, tui.ToolInfo{
Name: tool.Name,
Description: tool.Description,
Category: tool.Category,
})
}
sort.Slice(items, func(i, j int) bool {
return items[i].Name < items[j].Name
})
return items
}

func (w *nexusWorkspace) LoadMCPServers(_ context.Context) []tui.MCPServerInfo {
result := w.client.MCPResult()
if result == nil {
return nil
}
items := make([]tui.MCPServerInfo, 0, len(result.ServerResults))
for _, server := range result.ServerResults {
status := "ready"
errMsg := ""
if server.Error != nil {
status = "error"
errMsg = server.Error.Error()
}
items = append(items, tui.MCPServerInfo{
Name: server.Name,
ToolsRegistered: server.ToolsRegistered,
Status: status,
Error: errMsg,
})
}
sort.Slice(items, func(i, j int) bool {
return items[i].Name < items[j].Name
})
return items
}

func (w *nexusWorkspace) LoadSkills(_ context.Context) []tui.SkillInfo {
skills, err := skillspkg.All(w.workDir)
if err != nil {
return nil
}
items := make([]tui.SkillInfo, 0, len(skills))
for _, skill := range skills {
if !skill.UserInvocable {
continue
}
description := strings.TrimSpace(skill.Description)
if description == "" {
description = strings.TrimSpace(skill.WhenToUse)
}
items = append(items, tui.SkillInfo{
Name: skill.Name,
Description: description,
WhenToUse: strings.TrimSpace(skill.WhenToUse),
Source: string(skill.Source),
})
}
sort.Slice(items, func(i, j int) bool {
return items[i].Name < items[j].Name
})
return items
}

func (w *nexusWorkspace) Close() {
w.client.Close()
}
Expand Down Expand Up @@ -384,6 +458,7 @@ func (w *nexusWorkspace) onProgress(progress sdk.ToolProgress) {
ToolName: progress.ToolName,
Status: string(progress.Stage),
Label: label,
Metadata: progress.Metadata,
})
}

Expand Down Expand Up @@ -433,7 +508,7 @@ func runInteractive(ctx context.Context, options runtimeOptions) error {
}
defer ws.Close()

return tuimodel.Run(ws, ctx)
return tuiapp.Run(ws, ctx)
}

// buildTUIMonitoring creates a monitoring system that writes to a log file
Expand Down
Binary file modified docs/captures/commands_pannel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/captures/goal_ui/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/captures/home.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/captures/model_selction.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/captures/provider_config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/captures/working1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/captures/working2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
128 changes: 128 additions & 0 deletions docs/tui-roadmap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# TUI Roadmap

This note tracks the current UX progress of the Nexus CLI TUI and the next interaction work.

## Completed

### 1. Welcome wordmark cleanup
- Removed the extra leading bullet from the welcome screen wordmark.
- Status: done

### 2. Footer simplification
- Removed `ctrl+e` select mode from the visible happy path.
- Simplified the default footer actions.
- Tool navigation is no longer advertised as `tab chat/tools` in the primary footer flow.
- Status: done

### 3. Working status lane above composer
- Moved the active `working` indicator out of the header.
- Added a status lane directly above the composer for runtime visibility.
- The lane now focuses on runtime state only: `working`, `failed`, or `ready`.
- Status: done

### 4. Primary chat layout polish
- The app now uses near-full-width layout with small left/right margins instead of a narrow centered column.
- User messages use an inline blue `● >` marker.
- Assistant messages use an orange `●` marker.
- Intermediate assistant segments created around tool calls no longer show false `done` states.
- Final assistant metadata is attached only to the true end of the turn.
- Status: done

### 5. Tool rendering baseline
- Added richer tool summaries and previews for core tools.
- Kept completed tools visually more neutral so green is reserved for actual turn completion.
- Added a right-side details pane for selected tools.
- Status: done

### 6. Shared markdown renderer
- Switched from raw environment-configured glamour usage to a shared markdown helper in `internal/tui/common/markdown.go`.
- Added cached renderers by width and per-renderer locking, following the same structural idea as Crush.
- Kept a Nexus-specific style decision: markdown headings no longer show visible `##` / `###` prefixes in the main chat renderer.
- Status: done

## Partially Done

### 7. Footer token/context usage
- The footer now shows cumulative token usage for the current observed session in the TUI.
- Per-turn token usage is rendered on the final assistant meta line instead of duplicating it in multiple places.
- Remaining work:
- expose reliable model context-window capacity
- add a context percentage once that data is available
- Status: in progress

### 8. Commands / settings reorganization
- The footer has already been simplified and older noise removed.
- `ctrl+p` is now a true settings hub with nested sections for commands, providers, models, tools, MCP, and skills.
- Generic slash commands are no longer advertised there; slash input is now reserved for skills in the chat composer.
- The `Tools`, `MCP`, and `Skills` sections now load live data from the current workspace/runtime instead of showing only static placeholder copy.
- Status: done

## Next Priorities

### 9. Mouse-first selection and copy
- Implemented:
- mouse event routing in the main model
- drag-to-copy text selection in chat
- copy on mouse release
- persistent colored selection after mouse release
- double-click word selection
- triple-click line selection
- auto-scroll while dragging at viewport edges
- `ctrl+shift+c` copy shortcut
- right-click copy attempt when the terminal forwards the event
- accurate clipboard-availability notice when Linux clipboard backends are missing
- `ctrl+shift+c` copy shortcut
- right-click copy attempt when the terminal forwards the event
- accurate clipboard-availability notice when Linux clipboard backends are missing
- Remaining work:
- refine copy semantics for visual chat markers versus plain content where needed
- Status: in progress

### 10. Clickable tool rows and richer interactions
- Implemented:
- tool rows can now be clicked
- clicking a tool row selects it
- explicit click targets exist for expand and details
- thinking blocks can be expanded or collapsed directly with the mouse
- Remaining work:
- smoother IDE-like interactions around the side pane
- Status: in progress

### 11. Commands / settings panel expansion
- Completed:
- skills
- tools
- MCP
- model/provider settings
- session actions
- Remaining work:
- deepen each section into richer management views instead of simple searchable lists
- Status: in progress

### 11b. Manual compaction trigger
- A true manual compact action is still missing.
- The runtime currently auto-compacts, but the TUI/SDK surface does not yet expose a dedicated manual compaction API.
- Do not fake this with a normal prompt command; it should be a real engine operation once exposed.
- Candidate UX later:
- Settings / Commands entry: `Compact Context`
- optional shortcut such as `ctrl+l` once the runtime hook exists
- Status: planned

### 12. Context percentage and model capacity visibility
- Once model context capacity is reliably available in TUI state, show clear session usage such as:
- `12.4k total`
- `31% context`
- Status: planned

## Recommended Implementation Order

1. Mouse-first selection and copy behavior
2. Clickable tool rows and detail interactions
3. Commands/settings reorganization
4. Context-window percentage and model-capacity display

## Notes

- Crush remains the right reference for markdown renderer structure, mouse selection, and interaction polish.
- Nexus intentionally diverges from Crush on some visual choices, especially markdown heading presentation and chat chrome.
- `AGENTS.md` should stay focused on engineering rules; roadmap items belong in docs like this file.
4 changes: 3 additions & 1 deletion internal/tools/files/edit/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,9 @@ func (e *Tool) Call(
output["git_diff"] = gitDiff
}

return tool.NewJSONResult(output), nil
res := tool.NewJSONResult(output)
res.Metadata = &tool.ResultMetadata{Additional: output}
return res, nil
}

func normalizedBaseName(filePath string) string {
Expand Down
4 changes: 3 additions & 1 deletion internal/tools/files/write/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,9 @@ func (w *Tool) Call(
output["git_diff"] = gitDiff
}

return tool.NewJSONResult(output), nil
res := tool.NewJSONResult(output)
res.Metadata = &tool.ResultMetadata{Additional: output}
return res, nil
}

func nullableOriginal(oldContent string, fileExists bool) any {
Expand Down
Loading
Loading