Skip to content

Extract inline lipgloss styles and harden ShowWelcomeBanner styling#39246

Merged
pelikhan merged 3 commits into
mainfrom
copilot/extract-inline-lipgloss-styles
Jun 14, 2026
Merged

Extract inline lipgloss styles and harden ShowWelcomeBanner styling#39246
pelikhan merged 3 commits into
mainfrom
copilot/extract-inline-lipgloss-styles

Conversation

Copilot AI commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Two style fixes to stop bypassing the centralized pkg/styles abstraction: inline lipgloss.NewStyle() calls in the schedule-calendar renderer and unstyled output in ShowWelcomeBanner.

pkg/styles/theme.go

Added five named vars for schedule-calendar intensity levels, keeping style definitions in the styles layer:

  • ScheduleCalendarEmpty · ScheduleCalendarLow · ScheduleCalendarMedium · ScheduleCalendarHigh · ScheduleCalendarCritical

Also updated the schedule-calendar style comments to describe semantic intensity levels rather than embedding threshold logic.

pkg/styles/theme_wasm.go

Added wasm no-op stubs for the five new schedule-calendar styles so wasm builds have matching exported symbols:

  • ScheduleCalendarEmpty · ScheduleCalendarLow · ScheduleCalendarMedium · ScheduleCalendarHigh · ScheduleCalendarCritical

pkg/cli/compile_schedule_calendar.go

Replaced all six inline lipgloss.NewStyle() calls in intensityStyle() with the new styles.* vars. Non-terminal (no-ANSI) case uses the zero value lipgloss.Style{}.

// Before
case count == 0:
    return lipgloss.NewStyle().Foreground(styles.ColorComment)
// ...

// After
case count == 0:
    return styles.ScheduleCalendarEmpty
// ...

pkg/console/terminal.go

Styled the banner headline directly with styles.Header.Render(...) only when tty.IsStderrTerminal() is true (matching stderr output), and kept the description as plain text.

// Before
fmt.Fprintln(os.Stderr, "🚀 Welcome to GitHub Agentic Workflows!")
fmt.Fprintln(os.Stderr, description)

// After
header := "🚀 Welcome to GitHub Agentic Workflows!"
if tty.IsStderrTerminal() {
    header = styles.Header.Render(header)
}
fmt.Fprintln(os.Stderr, header)
fmt.Fprintln(os.Stderr, description)

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Extract inline lipgloss styles and style ShowWelcomeBanner Extract inline lipgloss styles and style ShowWelcomeBanner Jun 14, 2026
Copilot AI requested a review from pelikhan June 14, 2026 16:35
@pelikhan pelikhan marked this pull request as ready for review June 14, 2026 16:36
Copilot AI review requested due to automatic review settings June 14, 2026 16:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR centralizes terminal styling by moving schedule heatmap (“schedule calendar”) intensity styles into pkg/styles and by styling the interactive welcome banner output, reducing ad-hoc lipgloss.NewStyle() usage outside the styles layer.

Changes:

  • Added named schedule heatmap intensity styles to pkg/styles/theme.go.
  • Updated the schedule heatmap renderer to use the new centralized style variables and avoid ANSI in non-TTY output.
  • Styled ShowWelcomeBanner output using the console/styles abstractions.
Show a summary per file
File Description
pkg/styles/theme.go Adds named schedule calendar intensity styles to keep style definitions centralized.
pkg/cli/compile_schedule_calendar.go Replaces inline lipgloss.NewStyle() calls with the new styles.ScheduleCalendar* variables and uses a zero-value style for non-TTY output.
pkg/console/terminal.go Styles the welcome banner headline/description output to align with the console styling approach.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 3/3 changed files
  • Comments generated: 1

Comment thread pkg/console/terminal.go Outdated
Comment on lines +43 to +46
fmt.Fprintln(os.Stderr, "")
fmt.Fprintln(os.Stderr, "🚀 Welcome to GitHub Agentic Workflows!")
fmt.Fprintln(os.Stderr, applyStyle(styles.Header, "🚀 Welcome to GitHub Agentic Workflows!"))
fmt.Fprintln(os.Stderr, "")
fmt.Fprintln(os.Stderr, description)
fmt.Fprintln(os.Stderr, FormatInfoMessage(description))
@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

No test files were added or modified in this PR. The PR only changes production files: pkg/cli/compile_schedule_calendar.go, pkg/console/terminal.go, and pkg/styles/theme.go. Test Quality Sentinel skipped.

@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed for PR #39246: the PR does not have the implementation label (has_implementation_label=false) and has only 32 new lines of code in business logic directories, which is at or below the 100-line threshold (requires_adr_by_default_volume=false). Neither Condition A nor Condition B is met.

@github-actions github-actions Bot mentioned this pull request Jun 14, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /zoom-out and /improve-codebase-architecture — requesting changes on one correctness issue and two design concerns.

📋 Key Themes & Highlights

Key Issues

  • stderr/stdout TTY mismatch (terminal.go line 44): applyStyle checks tty.IsStdoutTerminal() but the output goes to os.Stderr. This can silently misfire — ANSI codes leaking into piped stderr, or missing styling when stdout is piped. ClearScreen/ClearLine in the same file use tty.IsStderrTerminal() as the correct precedent.
  • Semantic mismatch with FormatInfoMessage (terminal.go line 46): the "i " icon prefix belongs to notification-style messages, not to a banner description. The change unintentionally redefines the welcome screen's visual vocabulary.
  • Count thresholds leaked into style doc comments (theme.go): counts are intensityStyle's concern; keeping them out of theme.go docs makes both files independently maintainable.

Positive Highlights

  • ✅ Clean, mechanical 1:1 replacement of inline lipgloss.NewStyle() calls in intensityStyle() — correct and risk-free.
  • lipgloss.Style{} zero-value substitution for the non-terminal path is semantically equivalent and idiomatic.
  • ✅ Named constants follow the established pkg/styles naming convention perfectly.
  • ✅ Well-structured PR description with before/after snippets.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 202.8 AIC · ⌖ 13.5 AIC · ⊞ 29.4K

Comment thread pkg/console/terminal.go Outdated
ClearScreen()
fmt.Fprintln(os.Stderr, "")
fmt.Fprintln(os.Stderr, "🚀 Welcome to GitHub Agentic Workflows!")
fmt.Fprintln(os.Stderr, applyStyle(styles.Header, "🚀 Welcome to GitHub Agentic Workflows!"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/zoom-out] applyStyle uses isTTY()tty.IsStdoutTerminal(), but this function writes to os.Stderr. ClearScreen and ClearLine in the same file correctly guard on tty.IsStderrTerminal(). If the user pipes stdout (e.g. gh aw run ... | tee log), isTTY() returns false and the header renders unstyled; conversely, if stderr is redirected to a file while stdout is a terminal, ANSI codes leak into the file.

💡 Suggested fix

Either wrap the call in an explicit stderr TTY check:

header := "🚀 Welcome to GitHub Agentic Workflows!"
if tty.IsStderrTerminal() {
    header = styles.Header.Render(header)
}
fmt.Fprintln(os.Stderr, header)

Or add a complementary applyStderrStyle helper alongside applyStyle in console.go that gates on tty.IsStderrTerminal() — keeping the abstraction consistent.

Comment thread pkg/console/terminal.go Outdated
fmt.Fprintln(os.Stderr, applyStyle(styles.Header, "🚀 Welcome to GitHub Agentic Workflows!"))
fmt.Fprintln(os.Stderr, "")
fmt.Fprintln(os.Stderr, description)
fmt.Fprintln(os.Stderr, FormatInfoMessage(description))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/improve-codebase-architecture] FormatInfoMessage prepends a styled "i " icon, turning the workflow description into a notification-style info message. A welcome banner description is not an info notification — it is the workflow's purpose statement. Using FormatInfoMessage changes the visual contract of the banner and could confuse users who see info-prefix styling in a greeting context.

💡 Consider a neutral approach

For a welcome-banner description, plain text or a subtle wrap is more appropriate:

// Option A: keep it plain (matches the original intent)
fmt.Fprintln(os.Stderr, description)

// Option B: apply a muted/normal style without the "i " icon
if tty.IsStderrTerminal() {
    fmt.Fprintln(os.Stderr, styles.Muted.Render(description))
} else {
    fmt.Fprintln(os.Stderr, description)
}

Reserve FormatInfoMessage for actual informational notices, keeping the vocabulary consistent with the rest of the console package.

Comment thread pkg/styles/theme.go Outdated
var ScheduleCalendarEmpty = lipgloss.NewStyle().
Foreground(ColorComment)

// ScheduleCalendarLow style for low-trigger slots (count == 1) - cyan

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/improve-codebase-architecture] The doc comments embed the count thresholds from intensityStyle ("count == 1", "count 2–3", "count 4–6", "count 7+"). This couples the style definitions to a single caller's threshold values. If the thresholds in intensityStyle are ever adjusted, these comments silently become stale — or worse, mislead a future caller who reuses these vars for a different heatmap.

💡 Suggested wording

Document semantic intent only — leave threshold specifics to intensityStyle:

// ScheduleCalendarLow style for low-intensity calendar slots - cyan
var ScheduleCalendarLow = lipgloss.NewStyle().
    Foreground(ColorInfo)

// ScheduleCalendarMedium style for medium-intensity calendar slots - green
var ScheduleCalendarMedium = lipgloss.NewStyle().
    Foreground(ColorSuccess)

This keeps theme.go as a pure presentation layer and avoids leaking data-model details (count thresholds) into the style package.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two build-breaking issues must be fixed before this merges.

### Blocking issues

1. applyStyle undefined in wasm builds (already flagged in existing comment)

terminal.go has no build constraint so it compiles for every target, including js/wasm. applyStyle lives only in console.go (//go:build !js && !wasm), with no stub in console_wasm.go. Since pkg/parser and pkg/workflow import pkg/console, the wasm binary (make build-wasm) breaks immediately. The banner also gates styling on tty.IsStdoutTerminal() while writing to os.Stderr; the two should be co-fixed by guarding on tty.IsStderrTerminal() and using styles.Header.Render() directly.

2. Five new ScheduleCalendar* vars have no wasm stubs (see inline comment)

theme.go (!js && !wasm) adds ScheduleCalendarEmpty/Low/Medium/High/Critical. compile_schedule_calendar.go has no build constraint and references all five. theme_wasm.go has zero-value stubs for every other exported style var, but these five are missing — GOOS=js GOARCH=wasm go build ./... will fail.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • proxy.golang.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "proxy.golang.org"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer · 460.1 AIC · ⌖ 13.2 AIC · ⊞ 17.3K

Comment thread pkg/styles/theme.go
// Schedule calendar intensity styles for the heatmap renderer

// ScheduleCalendarEmpty style for zero-trigger slots - muted
var ScheduleCalendarEmpty = lipgloss.NewStyle().

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing wasm stubs for 5 new ScheduleCalendar* vars will break go build ./... under GOOS=js GOARCH=wasm.

theme.go has //go:build !js && !wasm, so these vars are invisible to wasm. compile_schedule_calendar.go has no build constraint and references all five: styles.ScheduleCalendarEmpty, ScheduleCalendarLow, ScheduleCalendarMedium, ScheduleCalendarHigh, ScheduleCalendarCritical. Any wasm build covering ./... will fail with undefined: styles.ScheduleCalendarEmpty (and four siblings).

💡 Suggested fix

Add the five stubs to pkg/styles/theme_wasm.go, matching the pattern already there:

// Schedule calendar intensity styles (no-op in Wasm)
var (
    ScheduleCalendarEmpty    = WasmStyle{}
    ScheduleCalendarLow      = WasmStyle{}
    ScheduleCalendarMedium   = WasmStyle{}
    ScheduleCalendarHigh     = WasmStyle{}
    ScheduleCalendarCritical = WasmStyle{}
)

Every other style var in theme.go has a corresponding stub in theme_wasm.go; the five new ones are the only exceptions.

@github-actions

Copy link
Copy Markdown
Contributor

Hey @Copilot 👋 — nice cleanup! Centralising the inline lipgloss.NewStyle() calls into named pkg/styles vars and applying consistent styling to ShowWelcomeBanner makes the styling layer much easier to reason about.

One thing that would strengthen this before merge:

  • Add tests — the diff touches intensityStyle() in compile_schedule_calendar.go and ShowWelcomeBanner in terminal.go, but no test files are included. A table-driven test for intensityStyle() covering each count branch (0, low, medium, high, critical) would confirm the style mappings are wired correctly after the refactor. A smoke-level test for ShowWelcomeBanner (e.g. capturing stderr and asserting the headline string is present) would guard the banner output.

If you'd like a hand, you can assign this prompt to your coding agent:

Add Go tests for the two functions changed in PR #39246:

1. pkg/cli/compile_schedule_calendar_test.go — table-driven test for intensityStyle().
   Cover every branch:
   - count == 0  → styles.ScheduleCalendarEmpty
   - 1 ≤ count ≤ 3  → styles.ScheduleCalendarLow
   - 4 ≤ count ≤ 6  → styles.ScheduleCalendarMedium
   - 7 ≤ count ≤ 9  → styles.ScheduleCalendarHigh
   - count ≥ 10  → styles.ScheduleCalendarCritical
   Use lipgloss.Style comparison (reflect.DeepEqual or .String()) to assert correctness.
   Also cover the noANSI path that returns lipgloss.Style{}.

2. pkg/console/terminal_test.go — test for ShowWelcomeBanner.
   Redirect os.Stderr to a buffer (or use a writer-injection refactor if needed),
   call ShowWelcomeBanner("test description"), and assert:
   - The output contains "Welcome to GitHub Agentic Workflows"
   - The output contains "test description"

Generated by ✅ Contribution Check · 503.3 AIC · ⌖ 13.6 AIC · ⊞ 24.7K ·

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jun 14, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

Done. I ran the PR finisher flow and pushed follow-up fixes in add907a (stderr-aware banner styling, removed wasm-incompatible applyStyle usage in ShowWelcomeBanner, and added missing wasm style stubs for ScheduleCalendar*). Local validation (make fmt, make lint, make test-unit, make test, make recompile) and parallel validation completed.

Copilot AI changed the title Extract inline lipgloss styles and style ShowWelcomeBanner Extract inline lipgloss styles and harden ShowWelcomeBanner styling Jun 14, 2026
@pelikhan pelikhan merged commit dfa60fa into main Jun 14, 2026
36 checks passed
@pelikhan pelikhan deleted the copilot/extract-inline-lipgloss-styles branch June 14, 2026 17:52
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.

3 participants