feat(log): add a rotating log file and show its path in the TUI - #14
Merged
Conversation
The library captures the process log stream in a LogBuffer for the TUI panel, but nothing reaches disk — once the TUI exits the run leaves no record to debug from. Add LogFileConfig and OpenLogFile, which return an io.Writer callers tee into their existing slog handler so the same lines land in both places. Rotation follows the Unix convention: the live file keeps its name and older generations shift down through <path>.1 … <path>.N before being discarded. A single write is never split across two generations, so a log line always lands whole in one file. *LogFile is nil-safe on every method and OpenLogFile returns nil when the file is disabled, so callers need no branching to turn it off. TUIConfig gains LogPath and ShowLogPath (default true), rendering " Logs (/path/to/file.log) " on the log panel divider. The path elides from the left and drops entirely on a terminal too narrow to hold it, so the divider always fits one row. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
govulncheck fails the pipeline on GO-2026-5856 (Encrypted Client Hello privacy leak in crypto/tls), which is fixed in go1.26.5. CI installs the toolchain from the go directive, so bumping it clears the finding. Same fix as db264ab, which bumped to 1.26.4 for GO-2026-5039. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
hoaitan
approved these changes
Aug 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
LogBufferkeeps the process log stream in memory for the TUI panel, but nothing reaches disk. Once the TUI exits the run leaves no record — there is nothing to go back to when debugging a reconnect, a bootstrap, or a crash that happened twenty minutes ago.Downstream,
retask-cliwants exactly this forretask sandbox connect: keep the TUI panel as-is, and additionally append every line toretask.login the working folder, with the active path visible on the Logs divider.What
LogFileConfig+OpenLogFile(newlogfile.go)The library still never installs a logger of its own.
OpenLogFilehands back anio.Writerthe caller tees into whatever handler already feeds the TUI:LogFile.EnabledtrueLogFile.Path<cwd>/agentfleet.logLogFile.MaxBytes10MB0disables rotation.LogFile.Backups50truncates instead.TUI.ShowLogPathtrueTUI.LogPathon the log panel divider.Rotation follows the Unix convention — the live file keeps its name, older generations shift down through
<path>.1,<path>.2, … up toBackups, and the oldest is discarded. A singleWriteis never split across two generations, so a log line always lands whole in one file. Reopening an existing file appends rather than truncating.*LogFileis nil-safe on every method andOpenLogFilereturnsnil, nilwhen disabled, so turning the file off needs no branching at the call site.TUI divider
TUIConfig.LogPath/ShowLogPathrender the path on the Logs divider:The path elides from the left as the terminal narrows, and drops entirely when there is no room, so the divider always occupies exactly one row:
Compatibility
Purely additive. Existing callers keep their current behaviour:
TUIConfig.LogPathis empty by default, so the divider still rendersLogs, and nothing opens a file unlessOpenLogFileis called.DefaultConfig()gains theLogFileblock andTUI.ShowLogPath: true, following the existing pattern forAutoOpen.Testing
go vet ./...,gofmt -l,go build ./...andgo test -race ./...all pass locally.New coverage: rotation at the threshold, generation shifting, discard beyond
Backups,Backups: 0truncation,MaxBytes: 0never rotating, oversized single writes, append-across-opens, absolute path resolution, write-after-close, concurrent writes under-race, nil-writer no-op, plus divider label rendering at wide, narrow and too-narrow terminal widths.Follow-up
A tagged release is needed before
nwebxyz/retask-clican consume this.🤖 Generated with Claude Code