Skip to content

feat(cli): lipgloss rendering, --save flag, and --help polish#6

Merged
birdmanmandbir merged 4 commits into
mainfrom
worker/611ae710
Apr 1, 2026
Merged

feat(cli): lipgloss rendering, --save flag, and --help polish#6
birdmanmandbir merged 4 commits into
mainfrom
worker/611ae710

Conversation

@birdmanmandbir

Copy link
Copy Markdown
Contributor

Summary

  • Lipgloss event rendering (cmd/render.go): styled output for command results (dim gray $ cmd, red exit N on failure with truncated output), retries (orange ↺ retry), and delta pass-through
  • Event rendering wired into stream (cmd/stream.go): EventCommandResult, EventRetry, EventDelta now use render functions; streamEndpoint returns (string, error) to capture the final response
  • --save flag (cmd/ask.go): pipes final ask response to flicknote add for note persistence; gracefully handles missing flicknote binary
  • Help text polish (cmd/ask.go, cmd/agent.go, cmd/daemon.go, cmd/sandbox.go): all commands now have Long descriptions with concrete examples and flag explanations
  • Docs updated (README.md, RULE.md): --save flag added to examples

Phases run

  • Phase 1: coder — implementation (all 4 code subtasks)
  • Phase 2: doc-writer — README.md, RULE.md updates
  • Phase 3: build + tests verified (go build ./..., go test ./... all pass)
  • skills/ei/SKILL.md skipped: path is in .gitignore (managed separately by ttal sync)

- Add cmd/render.go with lipgloss-styled event rendering (command results, retries, deltas)
- Wire renderCommandResult/renderRetry/renderDelta into streamEndpoint event loop
- Change streamEndpoint to return (string, error) for response capture
- Add --save flag to ei ask that pipes final response to flicknote add
- Polish --help Long descriptions for ask, agent run, daemon run, sandbox sync
- Update README.md and RULE.md with --save flag examples
…length

- gofmt cmd/agent.go (incorrect whitespace in Long string literal)
- Remove unused commandStyle and exitCodeStyle vars from cmd/render.go
- Break Long strings in cmd/daemon.go and cmd/sandbox.go to stay under 120 chars
@birdmanmandbir

Copy link
Copy Markdown
Contributor Author

pr-review-lead (round 5):

PR Review: feat: audit gaps in ttal→einai migration — prompts, UI polish, cmd docs, etc.

Critical Issues (2 found)

  • [silent-failures] cmd/ask.go:108-111saveAskResponse silently swallows flicknote exit errors. When flicknote exits non-zero (disk full, config error, validation failure), the function prints a warning to stderr but returns nil, making runAsk believe the save succeeded. User loses their response with no actionable error.

    // BUG: returns nil on actual save failure
    if execErr, ok := err.(*exec.ExitError); ok {
        fmt.Fprintf(os.Stderr, "flicknote warning: %s\n", string(execErr.Stderr))
        return nil  // ← should return an error
    }

    Fix: Return fmt.Errorf("flicknote exited with code %d: %s", execErr.ExitCode(), string(execErr.Stderr))

  • [silent-failures] cmd/ask.go:112-115 — Fragile platform-dependent string match for "not found". The string "exec: \"flicknote\": executable file not found in $PATH" differs across OS/Go versions. On Linux this may read differently; any Go version bump could break it silently.

    // BUG: brittle, platform-dependent
    if err.Error() == "exec: \"flicknote\": executable file not found in $PATH" {

    Fix: Use errors.Is(err, exec.ErrNotFound) (add "errors" import)

Important Issues (1 found)

  • [code, principles] cmd/render.go:14-17exitCodeStyle is defined but never used. The exit code is rendered with plain fmt.Fprintf instead:
    var exitCodeStyle = lipgloss.NewStyle().    // ← never referenced
        Foreground(lipgloss.Color("196")).Bold(true)
    // ...
    fmt.Fprintf(os.Stderr, "  exit %d\n", exitCode)  // ← unstyled
    Fix: Either apply exitCodeStyle to the exit code line, or remove the unused variable. Will likely cause a linter warning on CI.

Suggestions (3 found)

  • [comments] cmd/render.go:48 — Comment says "limits the output to 10 lines" but it actually limits to 10 meaningful (non-trailing-empty) lines. Update: // truncateOutput limits the output to 10 meaningful (non-empty) lines.

  • [principles] cmd/render.go:70 — Magic number 10 should be a named constant: const maxOutputLines = 10. Improves readability and tunability.

  • [principles] cmd/render.go:57-82truncateOutput is over-engineered: backward loop to count trailing empty lines + separate meaningful-line count adds complexity for minimal benefit. A simpler strings.Split + slice is sufficient.

Strengths

  • streamEndpoint return signature change is clean and correctly propagated to all callers
  • renderCommandResult / renderRetry / renderDelta separation is clear and readable
  • --save flag wiring is minimal and correct; agent path correctly ignores response (_, err = ...)
  • Help text improvements are well-written and include concrete examples
  • lipgloss v2 auto-detects TTY — no explicit color-detection code needed
  • go.mod/go.sum correctly promote charm.land/lipgloss/v2 from indirect to direct

Recommended Action

  1. Fix the two critical issues in saveAskResponse (nil return on exit error + errors.Is fix)
  2. Fix the unused exitCodeStyle (apply to exit code output, or remove)
  3. Address the minor suggestions if desired

The structure and approach are solid — these are targeted fixes.

- saveAskResponse: return error when flicknote exits non-zero (was silently swallowed)
- saveAskResponse: use errors.Is(err, exec.ErrNotFound) instead of brittle string match
- renderCommandResult: apply lipgloss styling to command line and exit code (were unstyled)
- render.go: extract maxOutputLines = 10 constant (removes magic number)
- truncateOutput: update doc comment to accurately describe behavior
@birdmanmandbir

Copy link
Copy Markdown
Contributor Author

code-lead (round 6):

Triage Update

Fixed

  • [silent-failures] nil return on flicknote exit errorsaveAskResponse now returns fmt.Errorf("flicknote exited with code %d: %s", ...) instead of silently swallowing the error (2a9347d)
  • [silent-failures] brittle string match for exec not found — replaced err.Error() == "exec: ..." with errors.Is(err, exec.ErrNotFound) (2a9347d)
  • [unused exitCodeStyle / unstyled exit code]exitCodeStyle var was already removed in the qlty lint fix (3f35472). Exit code line now styled inline with lipgloss.NewStyle().Foreground(Color("196")).Bold(true). Command line also styled inline (was plain fmt.Fprintf). (2a9347d)
  • [comments] truncateOutput comment inaccurate — updated to "limits output to 10 lines plus a summary of any remaining lines" (2a9347d)
  • [principles] magic number 10 — extracted as const maxOutputLines = 10 (2a9347d)

Deferred

  • [principles] truncateOutput over-engineered — backward loop to count trailing empty lines is deliberately handled to avoid counting trailing newlines as "more lines". Refactoring adds risk for minimal readability gain. Deferring.

@birdmanmandbir

Copy link
Copy Markdown
Contributor Author

pr-review-lead (round 7):

Re-review: fix(cli) — error handling, styling, and code quality

Fixed

  • [critical] nil return on flicknote exit errorsaveAskResponse now returns fmt.Errorf("flicknote exited with code %d: %s", ...) with trimmed stderr. (2a9347d)
  • [critical] brittle string match — replaced err.Error() == "exec: ..." with errors.Is(err, exec.ErrNotFound). Added "errors" import. (2a9347d)
  • [important] unused exitCodeStyle / unstyled exit code — removed unused package-level vars (commandStyle, exitCodeStyle). Both command line and exit code now styled inline via lipgloss.NewStyle()...Render(...). (3f35472, 2a9347d)
  • [suggestion] truncateOutput comment — updated to "limits output to 10 lines plus a summary of any remaining lines". (2a9347d)
  • [suggestion] magic number 10 — extracted as const maxOutputLines = 10. (2a9347d)

Deferred (accepted)

  • truncateOutput backward loop — coder's reasoning is sound: the backward scan explicitly avoids counting trailing newlines as "more lines", which is the correct behaviour. Deferral accepted.

Notes on new code

  • strings.TrimSpace on execErr.Stderr in the error message is a nice touch — prevents noisy trailing newlines in error output
  • Inline style creation (lipgloss.NewStyle().Foreground(...).Bold(true)) vs package-level vars is a minor inconsistency with retryStyle/outputStyle, but negligible for a CLI and well within acceptable range

VERDICT: LGTM ✅

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.

1 participant