Commit 06fe90b
Implement global UI formatter pattern for simplified output (#1714)
* Implement global UI formatter pattern for simplified output
This change introduces a global formatter pattern that makes UI output
as simple as logging, eliminating boilerplate and context fishing.
## Key Changes
### Global Formatter Pattern (pkg/ui/formatter.go)
- Added `ui.InitFormatter()` - called once at startup in root.go
- Package-level functions write output automatically:
- `ui.Success(text)` - writes to stderr with ✓ checkmark
- `ui.Error(text)` - writes to stderr with ✗ mark
- `ui.Warning(text)` - writes to stderr with ⚠ mark
- `ui.Info(text)` - writes to stderr with ℹ mark
- `ui.Data(text)` - writes plain text to stdout
- `ui.Markdown(content)` - renders and writes to stdout
- Advanced API via `ui.Format` variable for custom handling
### Simplified Commands
- about command (cmd/about/about.go) - now one line
- version command (internal/exec/version.go) - uses ui.Data()
- No more fmt.Println/Printf calls in commands
- No context fishing or fallback logic
### I/O Foundation (pkg/io/)
- New io.Context for channel management
- Separate Data (stdout) and UI (stderr) channels
- Terminal capability detection
- Secret masking support
### Documentation
- docs/io-and-ui-output.md - UI output guide
- docs/logging.md - Updated with UI vs logging distinction
- docs/prd/io-handling-strategy.md - Architecture decisions
## Key Principle
**UI output is required** - Without it, users can't use the command
**Logging is optional metadata** - Adds diagnostic context
## Migration
Old pattern (deprecated):
```go
ioCtx, ok := cmd.Context().Value(key).(io.Context)
formatter := ui.NewFormatter(ioCtx)
msg := formatter.Success("Done!")
fmt.Fprintf(ioCtx.UI(), "%s\n", msg)
```
New pattern:
```go
ui.Success("Done!") // One line, automatic output
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* Simplify UI output documentation, remove verbose old patterns
- Keep only new simplified ui.Success()/ui.Data() API
- Remove 600+ lines of verbose old I/O context examples
- Mention automatic masking briefly (implementation detail)
- Focus on what developers need: simple API reference and examples
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* Separate data and UI layers, both use I/O foundation
Create pkg/data/ package for data output:
- data.Write() - plain text to stdout
- data.Writef() - formatted text to stdout
- data.WriteJSON() - marshal and write JSON
- data.WriteYAML() - marshal and write YAML
UI package now only handles UI messages (stderr):
- ui.Success/Error/Warning/Info - status messages
- ui.Markdown/MarkdownMessage - formatted content
I/O package is the foundation for both:
- Channels (stdout/stderr separation)
- Masking (automatic secret redaction)
- Terminal capabilities (TTY detection, colors)
Architecture:
┌─────────────┐
│ Commands │
└──┬────────┬─┘
│ │
▼ ▼
┌────┐ ┌────┐
│ UI │ │Data│ Both use I/O
└─┬──┘ └─┬──┘
│ │
└───┬────┘
▼
┌─────┐
│ I/O │ Foundation
└─────┘
Updated:
- Version command uses data.WriteJSON/WriteYAML
- About command uses ui.Markdown
- Documentation reflects three-layer architecture
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* Rename InitData to InitWriter for consistency
Now both follow the same naming pattern:
- ui.InitFormatter(ioCtx)
- data.InitWriter(ioCtx)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* WIP: Start extracting terminal logic from I/O package
Created pkg/terminal/ package with:
- Terminal interface and implementation
- ColorProfile detection
- TTY detection, width/height
- Terminal title and alerts
- Config for terminal-specific settings
Removed Terminal() from io.Context interface - terminal capabilities
are UI concerns, not I/O concerns.
I/O package should only handle:
- Channels (stdin/stdout/stderr)
- Masking (secret redaction)
Terminal package handles:
- TTY detection
- Color capabilities
- Terminal dimensions
- Terminal control (title, alerts)
Still TODO:
- Update io.Config to remove terminal fields
- Remove Terminal interface from io/interfaces.go
- Update ui.Formatter to use terminal package
- Update all io.Terminal references
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* refactor(io): extract terminal detection to dedicated package
- Move terminal capability detection from pkg/io/ to pkg/terminal/
- Separate concerns: I/O handles channels+masking, terminal handles TTY/color/dimensions
- Update io.Context to remove Terminal() method and terminal field
- Simplify io.Config to only I/O concerns (RedirectStderr, DisableMasking)
- Update UI layer to create its own terminal instance
- Update formatter to use terminal.Terminal instead of io.Terminal
- Update all tests to use new terminal package
- Remove pkg/io/terminal.go and pkg/io/terminal_test.go
- Update example_test.go with correct usage patterns
Architecture:
┌─────────────┐
│ Commands │
└──┬────────┬─┘
│ │
▼ ▼
┌────┐ ┌────┐
│ UI │ │Data│
└─┬──┘ └─┬──┘
│ │
└───┬────┘
▼
┌─────┐
│ I/O │ Channels + Masking
└─────┘
▲
│
┌──────────┐
│ Terminal │ TTY/Color/Capabilities
└──────────┘
* refactor(io): implement centralized Write() for masking flow
Implement the core architecture where all output flows through io.Write() for automatic masking:
- Add io.Context.Write(stream, content) as central masking choke point
- Add io.Stream type (DataStream=0, UIStream=1) for stream routing
- Update Terminal interface to include Write() method
- Terminal.Write() flows through io.Write(UIStream) for masking
- Create io.TerminalWriter adapter to connect terminal→io without circular dependency
- Update UI package-level functions to use terminal.Write() flow
- Update InitFormatter() to wire terminal with I/O context
Flow architecture:
ui.Success() → terminal.Write() → io.Write(UIStream) → masking → stderr
data.Write() → io.Write(DataStream) → masking → stdout (next commit)
The terminal.IOWriter interface uses int for stream parameter to avoid
circular dependency, with values 0=Data and 1=UI matching io.Stream values.
This establishes the foundation for consistent masking across all output channels.
* refactor(data): implement data.Write() flow through io.Write()
Update data package to use centralized io.Write() for automatic masking:
- data.Write() → io.Write(DataStream) → masking → stdout
- data.Writef() → io.Write(DataStream) → masking → stdout
- data.WriteJSON() → io.Write(DataStream) → masking → stdout
- data.WriteYAML() → io.Write(DataStream) → masking → stdout
Add Write() method to mockTerminal in tests to satisfy terminal.Terminal interface.
All output now flows through io.Write() for centralized masking:
UI: ui.Success() → terminal.Write() → io.Write(UIStream) → stderr
Data: data.Write() → io.Write(DataStream) → stdout
Tests pass for pkg/io, pkg/ui, pkg/ui/heatmap, pkg/ui/markdown.
* docs(io): update architecture documentation with flow diagrams
Add comprehensive documentation for the new I/O architecture:
- Add mermaid diagram showing four-layer architecture (Commands → UI/Data → Terminal → I/O)
- Document the complete flow: ui.Success() → terminal.Write() → io.Write() → masking → stderr
- Add secret masking section with detailed flow diagram
- Explain how io.Write() is the central choke point for ALL output
- Document masking registration API and examples
- Show how masking works transparently across both UI and Data channels
Key architecture principles documented:
1. All output flows through io.Write() for centralized masking
2. Terminal handles UI output with capabilities (TTY, color, width)
3. Data writes directly to io.Write(DataStream)
4. Masking is automatic - no developer action required
Includes visual diagrams for:
- Overall architecture flow
- Masking process (io.Write → masker.Mask → ***MASKED*** → output)
* refactor(terminal,io): use sentinel errors and constants
Improvements:
- Add ANSI escape sequence constants (escBEL, escOSC, escST) in terminal package
- Update SetTitle() to use terminal.Write() instead of direct os.Stderr
- Update Alert() to use terminal.Write() instead of direct os.Stderr
- Add I/O sentinel errors: ErrBuildIOConfig, ErrUnknownStream, ErrWriteToStream, ErrMaskingContent
- Use sentinel error wrapping throughout io.Context.Write()
- Proper error chain: fmt.Errorf("%w: %w", sentinelErr, err)
All terminal control sequences now flow through io.Write() for consistency,
and all errors use standard sentinel error patterns for better error handling.
* refactor(ui): use constants for newlines, extract style selection, remove deprecated Output interface
Improvements:
- Add newline and tab character constants to avoid magic strings
- Extract markdown style selection logic into selectMarkdownStyle() function
- Remove deprecated Output interface that was never released
- Remove pkg/ui/output.go and pkg/ui/output_test.go
- Clean up unused io import in interfaces.go
Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* fix(ui,io,terminal): fix all remaining linter issues
Fix all remaining golangci-lint warnings:
1. hugeParam: Pass lipgloss.Style by pointer instead of by value (552 bytes)
- Updated StatusMessage signature to accept *lipgloss.Style
- Updated all callers to pass pointers
2. nilerr: Return error instead of swallowing it in RenderMarkdown
- Changed from returning nil to returning the actual error
- Maintains graceful degradation by returning content with error
3. revive: Add constant for AWS access key ID length
- Added awsAccessKeyIDLength = 20 constant
- Used constant instead of magic number
4. staticcheck: Remove empty if branch in test
- Simplified test to just call String() method
5. unparam: Change buildConfig to not return unused error
- Changed return type from (*Config, error) to *Config
- Updated all callers to match new signature
6. unused: Remove unused mockIOContext test helper
- Removed unused type and method from formatter_test.go
All tests passing, build successful.
Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* fix(io,terminal): fix color logic, partial writes, secrets in tests, and title management
Fixes identified in code review:
1. Terminal color precedence (terminal.go:359)
- Fixed inverted logic: Color=false was disabling color unconditionally
- Now: Color=true enables color, falls back to TTY default when unset
- Maintains proper precedence: NoColor > env vars > flags > config > TTY
2. Partial write handling (streams.go:99)
- Added check for partial writes in maskedWriter.Write()
- Returns io.ErrShortWrite if underlying write is incomplete
- Prevents silent data loss on partial writes
3. Embedded secrets in tests (masker_test.go:51-59, 108-116)
- Generate base64/URL encodings at runtime to avoid literal secrets
- Generate GitHub PAT at runtime (ghp_ + 36 chars) to avoid detection
- Test behavior unchanged, no hardcoded secrets remain
4. Terminal title management (terminal.go:226-267)
- Fixed TTY check: Now checks Stderr (where we write) not Stdout
- Added title tracking: Capture first title set as originalTitle
- RestoreTitle now actually restores the captured title
- Documented best-effort nature (can't query actual terminal title)
All tests passing, no breaking changes.
Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* fix(io,terminal,ui): improve error handling, masking, and initialization
**Formatter improvements:**
- Replace panic with proper nil-guard and sentinel error ErrUIFormatterNotInitialized
- Add defer renderer.Close() in RenderMarkdown to prevent resource leak
- Use concrete *formatter type to avoid runtime type assertions
**Root command I/O initialization:**
- Move I/O context and formatter initialization from Execute() to PersistentPreRun
- Ensures flags like --no-color, --redirect-stderr, --disable-masking are respected
- Flags are now parsed before I/O initialization, fixing precedence issues
**Masker enhancements:**
- Register both quoted and unquoted JSON variants to catch all encodings
- Update AWS secret pattern to use labeled pattern (AWS_SECRET_ACCESS_KEY) reducing false positives
- Support both AKIA (permanent) and ASIA (temporary) AWS access key prefixes
- Sort literals by length descending before masking to prevent partial replacement leaks
**Terminal improvements:**
- Add perf.Track to New() and all exported methods (Write, IsTTY, ColorProfile, Width, Height, SetTitle, RestoreTitle, Alert)
- Fix color profile detection to check stderr first (where UI is written), fall back to stdout
- Import pkg/perf for performance tracking
**Error handling:**
- Add ErrUIFormatterNotInitialized sentinel error to errors/errors.go
- Replace all string-based "ui formatter not initialized" errors with sentinel error
- All formatter wrapper functions now return err directly instead of wrapping in fmt.Errorf
* fix(io,terminal,ui): improve error handling, masking, and initialization
**Formatter improvements:**
- Replace panic with proper nil-guard and sentinel error ErrUIFormatterNotInitialized
- Add defer renderer.Close() in RenderMarkdown to prevent resource leak
- Store globalIO context and use concrete *formatter type to avoid runtime type assertions
**Root command I/O initialization:**
- Move I/O context and formatter initialization from Execute() to PersistentPreRun
- Ensures flags like --no-color, --redirect-stderr, --disable-masking are respected
- Flags are now parsed before I/O initialization, fixing precedence issues
**Masker enhancements:**
- Register both quoted and unquoted JSON variants to catch all encodings
- Update AWS secret pattern to use labeled pattern (AWS_SECRET_ACCESS_KEY) reducing false positives
- Support both AKIA (permanent) and ASIA (temporary) AWS access key prefixes
- Sort literals by length descending before masking to prevent partial replacement leaks
**Terminal improvements:**
- Add perf.Track to New() and all exported methods (Write, IsTTY, ColorProfile, Width, Height, SetTitle, RestoreTitle, Alert)
- Fix color profile detection to check stderr first (where UI is written), fall back to stdout
- Import pkg/perf for performance tracking
**Error handling:**
- Add ErrUIFormatterNotInitialized sentinel error to errors/errors.go
- Replace all string-based "ui formatter not initialized" errors with sentinel error
- All formatter wrapper functions now return err directly instead of wrapping in fmt.Errorf
* docs: update I/O handling documentation to reflect current implementation
**CLAUDE.md updates:**
- Add I/O and UI Usage section with package-level function examples
- Document data.Write(), data.Writef(), data.WriteJSON(), data.WriteYAML()
- Document ui.Write(), ui.Writef() for plain UI output (no icons/colors)
- Document ui.Success(), ui.Error(), ui.Warning(), ui.Info() for formatted UI output
- Document ui.Markdown() (stdout) and ui.MarkdownMessage() (stderr)
- Add decision tree for choosing correct output function
- Add anti-patterns showing what NOT to do (direct stream access)
**PRD updates (docs/prd/io-handling-strategy.md):**
- Update "Simplified Developer Interface" to show package-level functions instead of fmt.Fprintf
- Add "Why package-level functions?" rationale section
- Update "Core Interfaces - Presentation Layer" to document package-level functions
- Add ui.Write/Writef for raw UI output
- Update all usage patterns (Patterns 1-6) to use package-level functions
- Update "Developer Mental Model" decision tree with correct function names
- Add data.WriteJSON() and data.WriteYAML() throughout examples
- Clarify that Formatter interface is internal, commands use package functions
Both docs now accurately reflect the current implementation where:
- Commands use simple package-level functions (data.Write, ui.Success, etc.)
- No context retrieval or fmt.Fprintf needed
- Linter enforces usage of package functions
- Automatic I/O initialization in cmd/root.go PersistentPreRun
* feat(data,ui): add Writeln functions and comprehensive data package tests
**pkg/data changes:**
- Add Writeln() function - writes content with automatic newline to stdout
- Add comprehensive unit tests (data_test.go) with 92% coverage:
* TestWrite - plain text output
* TestWritef - formatted text output
* TestWriteln - text with automatic newline
* TestWriteJSON - JSON marshaling and output
* TestWriteYAML - YAML marshaling and output
* TestGetIOContext_Panic - panic when not initialized
- Add setupTestIO() test helper to reduce code duplication
- All tests use test streams to verify output goes to correct channel
- All tests verify stderr remains empty (no leakage)
**pkg/ui changes:**
- Add Write() - plain text to stderr (no icon, no color)
- Add Writef() - formatted text to stderr (no icon, no color)
- Add Writeln() - text with newline to stderr (no icon, no color)
- These complement existing Success/Error/Warning/Info functions
- Allows developers to write raw UI messages when icons/colors not needed
**Test strategy:**
- Use testStreams helper to mock io.Streams interface
- Capture stdout/stderr in buffers for verification
- Verify correct channel usage (data → stdout, ui → stderr)
- Test happy paths and edge cases (empty strings, nil values)
- Validate marshaled output (JSON/YAML parsing)
- setupTestIO() helper with cleanup to restore global context
- Add nolint:dupl directives for intentional test similarity
Coverage:
- pkg/data: 0% → 92% (from no tests to comprehensive coverage)
- pkg/ui: 37.5% → 35.8% (slight decrease due to new untested functions)
Next: Add tests for ui.Write/Writef/Writeln package-level functions
* docs: add Writeln functions to developer documentation
Update both CLAUDE.md and PRD with complete reference for Writeln functions:
**CLAUDE.md:**
- Add data.Writeln() - plain text with automatic newline to stdout
- Add ui.Writeln() - plain text with automatic newline to stderr
- Update decision tree to include Writeln functions
- Show cleaner examples without manual \n characters
**PRD (docs/prd/io-handling-strategy.md):**
- Add data.Writeln() to simplified developer interface
- Add ui.Writeln() to package-level functions section
- Update Pattern 1 (Data Output) to show Writeln usage
- Update Pattern 2 (UI Messages) to show Writeln usage
- Update decision tree with data.Writeln() and ui.Writeln()
- Clean up examples to use Writeln instead of manual newlines
Both docs now provide complete API reference for all output functions:
- data: Write, Writef, Writeln, WriteJSON, WriteYAML
- ui: Write, Writef, Writeln, Success, Error, Warning, Info, Markdown, MarkdownMessage
* test(ui): add comprehensive package-level function tests - 94% coverage
Add output_test.go with extensive tests for all package-level UI functions:
**Test Coverage:**
- pkg/ui: 35.8% → **94.0%** (58.2% increase!)
- pkg/data: 92.0% (maintained)
**Functions Tested:**
- Write(), Writef(), Writeln() - plain text to stderr
- Success(), Successf() - success messages
- Error(), Errorf() - error messages
- Warning(), Warningf() - warning messages
- Info(), Infof() - info messages
- Markdown(), Markdownf() - markdown to stdout
- MarkdownMessage(), MarkdownMessagef() - markdown to stderr
- InitFormatter() - initialization
- getFormatter() - formatter retrieval
**Test Scenarios:**
1. Happy paths - verify correct output to stdout/stderr
2. Error handling - test behavior when formatter not initialized
3. Edge cases - empty strings, large content, formatting edge cases
4. Channel isolation - ensure stdout/stderr don't leak between channels
**Test Strategy:**
- setupTestUI() helper creates test I/O context with buffers
- testStreams mocks io.Streams interface for output capture
- Cleanup functions restore global state after tests
- Table-driven tests for consistency
- Error path testing for uninitialized formatter
**Coverage Breakdown:**
- InitFormatter: 100%
- Write/Writef/Writeln: 75-100%
- Success/Error/Warning/Info: 80-100%
- Markdown functions: 77-100%
- Error paths: 100%
All tests passing with excellent coverage exceeding 90% target!
* docs: enhance I/O benefits in developer docs and add blog post
**CLAUDE.md enhancements:**
- Expand "Why this matters" section with comprehensive benefits
- Add "Zero-Configuration Degradation" section highlighting automatic features
- Add "Security & Reliability" section emphasizing automatic secret masking
- Add "Developer Experience" section showing what devs DON'T have to do
- Add "User Experience" section highlighting user-facing benefits
- Total: 4 benefit categories with 20+ specific advantages
**Blog post (website/blog/2025-10-26-zero-config-terminal-output.md):**
- Title: "Zero-Configuration Terminal Output: Write Once, Works Everywhere"
- Problem statement: Traditional CLI output pain points
- Solution: Atmos's automatic degradation approach
- Real-world before/after comparison (60% less code)
- Complete feature coverage:
* Color degradation (TrueColor → 256 → 16 → None)
* Width adaptation
* TTY detection
* Markdown rendering
* Automatic secret masking
* Channel separation
- Environment support (NO_COLOR, CLICOLOR, FORCE_COLOR, etc.)
- Testing benefits
- Migration guide with complete API reference
- Architecture diagram
- Performance notes
- Future roadmap
Both docs now effectively sell the zero-configuration story:
- Write code once assuming full TTY
- System automatically degrades for all environments
- No manual capability checking
- No manual secret masking
- Perfect for CI, pipes, redirects, accessibility
* feat(terminal): add --force-tty and --force-color flags for screenshot generation
Add `--force-tty` and `--force-color` flags with ATMOS_FORCE_TTY, ATMOS_FORCE_COLOR, and CLICOLOR_FORCE env vars to force TTY mode and TrueColor output for screenshot generation.
**Key Features:**
- --force-tty: Forces TTY mode with sane defaults (width=120, height=40)
- --force-color: Forces TrueColor even for non-TTY
- CLICOLOR_FORCE and ATMOS_FORCE_COLOR are equivalent
**Bug Fix:**
- Fixed --color and terminal.color to respect TTY detection
- Previously forced color even for non-TTY, now only enables if TTY
**Implementation:**
- Added flags to cmd/root.go with environment variable bindings
- Updated pkg/terminal/terminal.go with force logic
- Created comprehensive test suite (14 tests, 94% coverage)
- Added nolint directives for cyclomatic complexity
**Documentation:**
- Updated CLAUDE.md, blog post, global-flags.mdx, terminal.mdx
- Added examples and use cases for screenshot generation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* test: regenerate CLI help snapshots after I/O refactoring
Regenerated golden snapshots for help command tests to reflect new terminal output formatting from I/O refactoring.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* refactor(io,terminal): remove deprecated types and fix comment style
**StreamType and Channel removal:**
- Delete StreamType and Channel types that were never released to main
- Stream is now the canonical I/O stream type
- Remove tests for deleted types from context_test.go
**Terminal improvements:**
- Update color profile detection comment to clarify Stderr-first check
- Add period to initialization comments per godot linter
**Comment style fixes:**
- Add periods to all inline comments in pkg/io/example_test.go
- Ensures godot linter compliance throughout
Since pkg/io/ is entirely new in this PR (never released to main), we don't need deprecation markers for types being removed. Stream is the canonical type going forward.
* docs(prd): update I/O handling strategy to use Stream instead of Channel
- Replace Channel type with Stream throughout PRD
- Update Terminal interface parameter names from channel to stream
- Fix code example to use terminal.Stdout instead of io.DataChannel
- Aligns PRD with actual implementation after removing deprecated types
* fix(terminal,schema): fix color precedence logic and update blog authorship
**Terminal color precedence fixes:**
- Fix IsColorEnabled() in pkg/schema/schema.go to accept isTTY parameter
- NoColor=true → force disable color
- Color=true → force enable color (even if non-TTY)
- Color=false (unset) → fall back to isTTY parameter
- Update call site in cmd/root.go to pass stderr TTY detection
- Update tests in pkg/schema/schema_test.go with new test cases
**Terminal test fixes:**
- Fix TestShouldUseColor_WithForceColor in pkg/terminal/terminal_test.go
- Correctly test NO_COLOR environment variable (EnvNoColor) not --no-color flag
- NO_COLOR env var takes precedence over --force-color
- Add proper assertions instead of discarding result
- Update test names and comments for clarity
**Blog post authorship:**
- Add osterman to website/blog/authors.yml with GitHub profile
- Update blog post author from cloudposse to osterman
- Update CLAUDE.md with blog authorship guidelines:
- Author should be the committer (PR opener)
- Use GitHub username, not generic "atmos" or "cloudposse"
- Add author to authors.yml if not present
All tests pass. Fixes color detection logic to properly respect TTY detection as fallback when color settings are not explicitly set.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* test(io): add Stream.String() test to increase coverage to 81.7%
Add table-driven test for Stream.String() method covering:
- DataStream returns "data"
- UIStream returns "ui"
- Unknown stream returns "unknown"
Coverage increased from 78.4% to 81.7%, exceeding 80% minimum requirement.
interfaces.go String() method now has 100% coverage.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* fix(terminal): NO_COLOR takes precedence over --force-color
**Terminal color precedence fix:**
- Update terminal.New() in pkg/terminal/terminal.go to check NO_COLOR before --force-color
- NO_COLOR environment variable now correctly overrides --force-color flag
- Priority order: NO_COLOR (highest) → --force-color → standard detection
- Use switch statement instead of if-else chain (gocritic)
- Add comprehensive test case in pkg/terminal/terminal_test.go using t.Setenv
**Documentation updates:**
- Update website/docs/cli/global-flags.mdx with clear precedence order
- Document that NO_COLOR takes highest precedence in flag descriptions
- Clarify precedence in environment variables section
- Add notes to --force-color and ATMOS_FORCE_COLOR sections
**Blog post improvements:**
- Revise intro in website/blog/2025-10-26-zero-config-terminal-output.md
- Remove "We're excited to announce" language
- Focus on value proposition: automatic adaptation and transparent handling
All terminal tests pass including new NO_COLOR precedence test case.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* docs(blog): emphasize secret masking and Charm Bracelet complementarity
Add section explaining what existing rendering libraries (Charm Bracelet/Lip Gloss)
don't solve that Atmos addresses:
- Automatic secret masking across all output channels
- Centralized I/O control with security-first design
- Infrastructure-specific requirements (AWS keys, API tokens, sensitive configs)
Clarify that Atmos's I/O system complements Charm Bracelet rather than replacing it:
- Lip Gloss handles beautiful rendering
- Atmos adds infrastructure-critical layer: centralized I/O with automatic secret masking
Highlight that secret masking was the primary driver for this work, addressing security
concerns specific to infrastructure tools.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* docs(blog): address feedback on terminal output blog post
**Code examples improvements:**
- Replace raw ANSI escape codes with Charm Bracelet's Lip Gloss examples
- Show realistic "before" patterns using lipgloss for styling
- Update "Old Pattern" migration guide to reflect actual main branch code (not intermediate PR state)
- Update "Try It Now" section with realistic lipgloss comparison
**Content improvements:**
- Remove "60% less code" unsubstantiated claim → "Dramatically less code"
- Add "Logging vs Terminal Output" section explaining distinction between ui.*/data.* (terminal) and log.* (logging)
- Link to Logging Configuration documentation
- Clarify terminal output respects TTY/color, logging doesn't
**Link fixes:**
- Fix broken /discussions link → /issues/new and Slack invite
- Update feedback section with working links
All changes make the blog post more accurate and show we're complementing (not replacing)
Charm Bracelet's excellent rendering libraries.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* fix(blog): correct broken logging configuration link
Replace broken link /cli/configuration/logging with correct links:
- /cli/configuration (logs section)
- /cli/global-flags (--logs-level and --logs-file flags)
The logging.mdx file doesn't exist; logging configuration is documented in the
main configuration file and global flags page.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
---------
Co-authored-by: Claude <[email protected]>1 parent b9e8e59 commit 06fe90b
File tree
69 files changed
+10434
-75
lines changed- cmd
- about
- internal
- docs
- prd
- secrets-masking
- errors
- internal
- exec
- tui/utils
- pkg
- data
- io
- schema
- terminal
- ui
- tests/snapshots
- website
- blog
- docs/cli
- configuration
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
69 files changed
+10434
-75
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
125 | 125 | | |
126 | 126 | | |
127 | 127 | | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
128 | 292 | | |
129 | 293 | | |
130 | 294 | | |
| |||
353 | 517 | | |
354 | 518 | | |
355 | 519 | | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
356 | 525 | | |
357 | 526 | | |
358 | 527 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
18 | | - | |
19 | | - | |
| 18 | + | |
20 | 19 | | |
21 | 20 | | |
22 | 21 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
5 | | - | |
6 | | - | |
7 | 4 | | |
8 | 5 | | |
9 | 6 | | |
10 | 7 | | |
11 | | - | |
| 8 | + | |
| 9 | + | |
12 | 10 | | |
13 | 11 | | |
14 | 12 | | |
15 | | - | |
16 | | - | |
17 | | - | |
18 | | - | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
19 | 17 | | |
20 | | - | |
21 | | - | |
| 18 | + | |
| 19 | + | |
22 | 20 | | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | 21 | | |
38 | 22 | | |
39 | 23 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
12 | 18 | | |
13 | 19 | | |
14 | 20 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| 29 | + | |
29 | 30 | | |
| 31 | + | |
30 | 32 | | |
31 | 33 | | |
32 | 34 | | |
33 | 35 | | |
34 | 36 | | |
35 | 37 | | |
| 38 | + | |
36 | 39 | | |
37 | 40 | | |
38 | 41 | | |
| |||
189 | 192 | | |
190 | 193 | | |
191 | 194 | | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
192 | 204 | | |
193 | 205 | | |
194 | 206 | | |
| |||
257 | 269 | | |
258 | 270 | | |
259 | 271 | | |
260 | | - | |
| 272 | + | |
| 273 | + | |
261 | 274 | | |
262 | 275 | | |
263 | 276 | | |
| |||
674 | 687 | | |
675 | 688 | | |
676 | 689 | | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
677 | 693 | | |
678 | 694 | | |
679 | 695 | | |
| |||
687 | 703 | | |
688 | 704 | | |
689 | 705 | | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
690 | 719 | | |
691 | 720 | | |
692 | 721 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
659 | 659 | | |
660 | 660 | | |
661 | 661 | | |
| 662 | + | |
662 | 663 | | |
663 | 664 | | |
664 | 665 | | |
0 commit comments