Conversation
…nes) Automatically fold messages exceeding 20 lines in the viewport, showing a stylish expand hint with hidden line count. Press Ctrl+P to toggle. - Add `collapsed` field to logEntry with pre-estimation at entry creation - Apply collapse in glamour-rendered AI responses and bordered user messages - Add `Ctrl+P` keybinding in command mode to toggle the first visible entry - Add collapse hint styles (CollapseHintLine / CollapseHintText) in both dark and light themes - Update help dialog (EN/ZH) to document the new shortcut Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ey handling The delete confirmation dialog (triggered by `d` in history mode) was broken in two ways: - The View renderer returned the history view before the dialog overlay, so the confirmation was never visible. - The Update router intercepted all keystrokes for history mode, preventing the DialogStack key handler from processing confirm/cancel. Fix by rendering the dialog overlay ahead of history mode and skipping the history dispatch when a dialog is active on the stack. Also add the `d: delete` shortcut hint to the title bar. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create a centralized mode-aware logging package (internal/logging) that
routes slog output to ~/.codeactor/logs/app-{date}.log in TUI mode
instead of stdout/stderr, which interferes with the bubbletea TUI display.
Key changes:
- New internal/logging/logger.go: mode-aware Init() with TUI (file-only)
and HTTP (stderr+file) modes, with io.Discard safety net in init()
- main.go: replace os.Stdout handler with io.Discard in init(), call
logging.Init() in runTUI/runHTTP
- internal/agents/tool_logger.go: use logging.GetFallbackWriter() instead
of os.Stdout as fallback to prevent terminal pollution in TUI mode
- internal/llm/llm.go: use logging.GetLogDir() for path consistency
- Migrate all fmt.Printf/fmt.Fprintf(os.Stderr) to slog calls across
dict, repo-knowledge, skills, and tui packages
Reviewer's GuideImplements collapsible rendering for long TUI messages (AI and user), introduces a centralized, mode-aware logging subsystem to avoid stdout corruption in TUI mode while unifying log paths, and replaces ad-hoc printf logging with structured slog usage across components. Sequence diagram for collapsible TUI message rendering and togglesequenceDiagram
actor User
participant TUIModel as model
participant Viewport
participant LogEntry as logEntry
participant GlamourRenderer as glamourRenderer
User->>TUIModel: key ctrl+p
TUIModel->>TUIModel: Update(msg)
TUIModel->>TUIModel: toggleCollapseAtViewport()
TUIModel->>LogEntry: collapsed = !collapsed
TUIModel->>LogEntry: clearRenderCache()
TUIModel->>Viewport: rebuildViewportPreservingScroll()
User->>TUIModel: next frame render
TUIModel->>TUIModel: renderSingleEntry(entry, width)
alt ai_response
TUIModel->>GlamourRenderer: Render(entry.content)
GlamourRenderer-->>TUIModel: rendered
TUIModel->>TUIModel: collapseContent(rendered, entry, collapseMaxLines)
TUIModel->>LogEntry: setCachedRender(collapsed, width)
else user_message
TUIModel->>TUIModel: renderUserMessageBoxCollapsible(content, width, entry)
TUIModel->>LogEntry: setCachedRender(rendered, width)
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- In
restoreSessionyou pre-collapse entries witheventType == "ai_response" || eventType == "user_input", but elsewhere the code consistently uses"user_message"(e.g.,submitTaskWithContent,submitFollowUp,toggleCollapseAtViewport), so restored user messages likely won’t collapse as intended; consider aligning the event type checks. - You added
CollapseHintLine/CollapseHintTextstyles incommon/styles.gobut the collapse hint rendering currently uses the globalcollapseHintLineStyle/collapseHintTextStyleintui_model.go; it would be cleaner to consolidate on one style source (preferably the sharedStylesstruct) or remove the unused fields. - The comment on
logEntry.collapsedsays "folded (>15 lines)" whilecollapseMaxLinesis set to 20 and used throughout; updating the comment or making the threshold configurable would keep this consistent and avoid confusion.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `restoreSession` you pre-collapse entries with `eventType == "ai_response" || eventType == "user_input"`, but elsewhere the code consistently uses `"user_message"` (e.g., `submitTaskWithContent`, `submitFollowUp`, `toggleCollapseAtViewport`), so restored user messages likely won’t collapse as intended; consider aligning the event type checks.
- You added `CollapseHintLine`/`CollapseHintText` styles in `common/styles.go` but the collapse hint rendering currently uses the global `collapseHintLineStyle`/`collapseHintTextStyle` in `tui_model.go`; it would be cleaner to consolidate on one style source (preferably the shared `Styles` struct) or remove the unused fields.
- The comment on `logEntry.collapsed` says "folded (>15 lines)" while `collapseMaxLines` is set to 20 and used throughout; updating the comment or making the threshold configurable would keep this consistent and avoid confusion.
## Individual Comments
### Comment 1
<location path="internal/tui/tui_history.go" line_range="376-377" />
<code_context>
entry.content = msg.Content
}
+ // Pre-collapse long ai_response and user_input entries
+ if entry.eventType == "ai_response" || entry.eventType == "user_input" {
+ if strings.Count(entry.content, "\n") >= collapseMaxLines {
+ entry.collapsed = true
</code_context>
<issue_to_address>
**issue (bug_risk):** Inconsistent eventType string for user messages may break collapse behavior in history view
This path uses "user_input" while other user messages use "user_message" (e.g. in submitTaskWithContent/submitFollowUp and toggleCollapseAtViewport). As a result, restored user messages may not be recognized as collapsible or rendered consistently. Consider switching to "user_message" here or handling both values to keep behavior aligned between live and restored sessions.
</issue_to_address>
### Comment 2
<location path="internal/tui/tui_model.go" line_range="209-210" />
<code_context>
resultBrief string // brief result description (e.g., "120 lines", "modified")
diffText string // unified diff content for file edit results
renderedCache map[int]string // width-keyed cache: key=width, value=rendered content
+ collapsed bool // true if content is currently folded (>15 lines)
compactData *CompactData
</code_context>
<issue_to_address>
**nitpick (typo):** Collapsed field comment is out of sync with collapseMaxLines constant
This still hard-codes ">15 lines" while collapseMaxLines is 20. Please update the comment to reference collapseMaxLines (or remove the specific number) so it stays accurate if the threshold changes.
```suggestion
renderedCache map[int]string // width-keyed cache: key=width, value=rendered content
collapsed bool // true if content is currently folded (exceeds collapseMaxLines)
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| // Pre-collapse long ai_response and user_input entries | ||
| if entry.eventType == "ai_response" || entry.eventType == "user_input" { |
There was a problem hiding this comment.
issue (bug_risk): Inconsistent eventType string for user messages may break collapse behavior in history view
This path uses "user_input" while other user messages use "user_message" (e.g. in submitTaskWithContent/submitFollowUp and toggleCollapseAtViewport). As a result, restored user messages may not be recognized as collapsible or rendered consistently. Consider switching to "user_message" here or handling both values to keep behavior aligned between live and restored sessions.
| renderedCache map[int]string // width-keyed cache: key=width, value=rendered content | ||
| collapsed bool // true if content is currently folded (>15 lines) |
There was a problem hiding this comment.
nitpick (typo): Collapsed field comment is out of sync with collapseMaxLines constant
This still hard-codes ">15 lines" while collapseMaxLines is 20. Please update the comment to reference collapseMaxLines (or remove the specific number) so it stays accurate if the threshold changes.
| renderedCache map[int]string // width-keyed cache: key=width, value=rendered content | |
| collapsed bool // true if content is currently folded (>15 lines) | |
| renderedCache map[int]string // width-keyed cache: key=width, value=rendered content | |
| collapsed bool // true if content is currently folded (exceeds collapseMaxLines) |
Summary by Sourcery
Introduce collapsible rendering for long TUI messages and centralize mode-aware logging to avoid corrupting the TUI while improving log consistency across components.
New Features:
Enhancements: