Repository: cloudposse/atmos
Pull request #1215: add pager for describe component
Author: login: samtholiya
Labels: name: minor
description: New features that do not break anything
Created: 2025-04-23T21:19:45Z | Merged: 2025-05-16T12:32:04Z

## what

* We are adding pager to `atmos describe component`
* We fixed the bug in the function that would assume the data is always atmosConfig and then use it to Highlight the data. This was all good if the data is atmosConfig but not for other cases.
* 
![image](https://github.com/user-attachments/assets/f1324365-f5a7-4440-9f7a-44defc4b4109)

## why

* We want user to give a consistent experience.

## references

* [DEV-2958](https://linear.app/cloudposse/issue/DEV-2958/implement-native-pager-for-all-atmos-describe-commands-and-help)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced a pager option for the `describe component` command, enabling paged output with syntax highlighting for YAML and JSON formats.
  - Enhanced output formatting with customizable syntax highlighting based on user configuration.
- **Bug Fixes**
  - Improved argument validation and error handling for CLI commands.
- **Documentation**
  - Added documentation for the new `--pager` flag in the `describe component` command.
- **Tests**
  - Added unit and integration tests covering pager functionality, output formatting, and CLI command execution.
- **Refactor**
  - Refactored command execution and output handling for improved modularity, testability, and configuration management.
  - Updated output functions to accept configuration context for consistent formatting and highlighting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/Makefile b/Makefile
index b1414ec8a3..b3c297e295 100644
--- a/Makefile
+++ b/Makefile
@@ -61,7 +61,7 @@ testacc: get
 
 testacc-cover: get
 	@echo "Running tests with coverage"
-	go test $(TEST) -v $(TESTARGS) -timeout 20m -coverprofile=coverage.out.tmp
+	go test $(TEST) -v -coverpkg=./... $(TESTARGS) -timeout 20m -coverprofile=coverage.out.tmp
 	cat coverage.out.tmp | grep -v "mock_" > coverage.out
 
 # Run acceptance tests with coverage report
diff --git a/cmd/describe.go b/cmd/describe.go
index 20f3851277..b080e3e153 100644
--- a/cmd/describe.go
+++ b/cmd/describe.go
@@ -15,7 +15,7 @@ var describeCmd = &cobra.Command{
 
 func init() {
 	describeCmd.PersistentFlags().StringP("query", "q", "", "Query the results of an `atmos describe` command using `yq` expressions")
-	describeCmd.PersistentFlags().String("pager", "true", "Disable the paging user experience")
+	describeCmd.PersistentFlags().String("pager", "true", "Disable / Enable the paging user experience")
 
 	RootCmd.AddCommand(describeCmd)
 }
diff --git a/cmd/describe_component.go b/cmd/describe_component.go
index 31ac30e359..3022f51c33 100644
--- a/cmd/describe_component.go
+++ b/cmd/describe_component.go
@@ -1,6 +1,8 @@
 package cmd
 
 import (
+	"errors"
+
 	"github.com/spf13/cobra"
 
 	e "github.com/cloudposse/atmos/internal/exec"
@@ -13,14 +15,51 @@ var describeComponentCmd = &cobra.Command{
 	Short:              "Show configuration details for an Atmos component in a stack",
 	Long:               `Display the configuration details for a specific Atmos component within a designated Atmos stack, including its dependencies, settings, and overrides.`,
 	FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
-	Run: func(cmd *cobra.Command, args []string) {
+	Args:               cobra.ExactArgs(1),
+	RunE: func(cmd *cobra.Command, args []string) error {
 		// Check Atmos configuration
 		checkAtmosConfig()
 
-		err := e.ExecuteDescribeComponentCmd(cmd, args)
+		if len(args) != 1 {
+			return errors.New("invalid arguments. The command requires one argument `component`")
+		}
+
+		flags := cmd.Flags()
+
+		stack, err := flags.GetString("stack")
+		checkFlagNotPresentError(err)
+		format, err := flags.GetString("format")
+		checkFlagNotPresentError(err)
+		file, err := flags.GetString("file")
+		checkFlagNotPresentError(err)
+		processTemplates, err := flags.GetBool("process-templates")
+		checkFlagNotPresentError(err)
+		processYamlFunctions, err := flags.GetBool("process-functions")
+		checkFlagNotPresentError(err)
+		query, err := flags.GetString("query")
+		checkFlagNotPresentError(err)
+		skip, err := flags.GetStringSlice("skip")
+		checkFlagNotPresentError(err)
+		pager, err := flags.GetString("pager")
+		checkFlagNotPresentError(err)
+
+		component := args[0]
+
+		err = e.NewDescribeComponentExec().ExecuteDescribeComponentCmd(e.DescribeComponentParams{
+			Component:            component,
+			Stack:                stack,
+			ProcessTemplates:     processTemplates,
+			ProcessYamlFunctions: processYamlFunctions,
+			Skip:                 skip,
+			Query:                query,
+			Pager:                pager,
+			Format:               format,
+			File:                 file,
+		})
 		if err != nil {
 			u.PrintErrorMarkdownAndExit("", err, "")
 		}
+		return nil
 	},
 	ValidArgsFunction: ComponentsArgCompletion,
 }
@@ -28,7 +67,7 @@ var describeComponentCmd = &cobra.Command{
 func init() {
 	describeComponentCmd.DisableFlagParsing = false
 	AddStackCompletion(describeComponentCmd)
-	describeComponentCmd.PersistentFlags().StringP("format", "f", "yaml", "The output format (`yaml` is default)")
+	describeComponentCmd.PersistentFlags().StringP("format", "f", "yaml", "The output format")
 	describeComponentCmd.PersistentFlags().String("file", "", "Write the result to the file")
 	describeComponentCmd.PersistentFlags().Bool("process-templates", true, "Enable/disable Go template processing in Atmos stack manifests when executing the command")
 	describeComponentCmd.PersistentFlags().Bool("process-functions", true, "Enable/disable YAML functions processing in Atmos stack manifests when executing the command")
@@ -41,3 +80,11 @@ func init() {
 
 	describeCmd.AddCommand(describeComponentCmd)
 }
+
+// checkFlagNotPresentError checks if the error is nil.
+// we prefer to panic because this is a developer error.
+func checkFlagNotPresentError(err error) {
+	if err != nil {
+		panic(err)
+	}
+}
diff --git a/internal/exec/atlantis_generate_repo_config.go b/internal/exec/atlantis_generate_repo_config.go
index 4efbe50d86..e629e4e4c2 100644
--- a/internal/exec/atlantis_generate_repo_config.go
+++ b/internal/exec/atlantis_generate_repo_config.go
@@ -525,7 +525,7 @@ specified in the ` + "`" + `integrations.atlantis.config_templates` + "`" + ` se
 			return err
 		}
 	} else {
-		err = u.PrintAsYAML(atlantisYaml)
+		err = u.PrintAsYAML(&atmosConfig, atlantisYaml)
 		if err != nil {
 			return err
 		}
diff --git a/internal/exec/atmos.go b/internal/exec/atmos.go
index 1dd47bbc51..f500baaafb 100644
--- a/internal/exec/atmos.go
+++ b/internal/exec/atmos.go
@@ -108,7 +108,7 @@ func ExecuteAtmosCmd() error {
 		if err != nil {
 			return err
 		}
-		err = u.PrintAsYAML(data)
+		err = u.PrintAsYAML(&atmosConfig, data)
 		if err != nil {
 			return err
 		}
@@ -120,7 +120,7 @@ func ExecuteAtmosCmd() error {
 		if err != nil {
 			return err
 		}
-		err = u.PrintAsYAML(data)
+		err = u.PrintAsYAML(&atmosConfig, data)
 		if err != nil {
 			return err
 		}
diff --git a/internal/exec/describe_affected.go b/internal/exec/describe_affected.go
index 288c6943fb..ecea508f9c 100644
--- a/internal/exec/describe_affected.go
+++ b/internal/exec/describe_affected.go
@@ -205,6 +205,16 @@ func parseDescribeAffectedCliArgs(cmd *cobra.Command, args []string) (DescribeAf
 
 // ExecuteDescribeAffectedCmd executes `describe affected` command
 func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error {
+	info, err := ProcessCommandLineArgs("", cmd, args, nil)
+	if err != nil {
+		return err
+	}
+
+	atmosConfig, err := cfg.InitCliConfig(info, true)
+	if err != nil {
+		return err
+	}
+
 	a, err := parseDescribeAffectedCliArgs(cmd, args)
 	if err != nil {
 		return err
@@ -271,7 +281,7 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error {
 	if a.Query == "" {
 		a.Logger.Trace("\nAffected components and stacks: \n")
 
-		err = printOrWriteToFile(a.Format, a.OutputFile, affected)
+		err = printOrWriteToFile(&atmosConfig, a.Format, a.OutputFile, affected)
 		if err != nil {
 			return err
 		}
@@ -314,7 +324,7 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error {
 			return err
 		}
 
-		err = printOrWriteToFile(a.Format, a.OutputFile, res)
+		err = printOrWriteToFile(&atmosConfig, a.Format, a.OutputFile, res)
 		if err != nil {
 			return err
 		}
diff --git a/internal/exec/describe_component.go b/internal/exec/describe_component.go
index 245907f1c2..4333845ed4 100644
--- a/internal/exec/describe_component.go
+++ b/internal/exec/describe_component.go
@@ -1,66 +1,71 @@
 package exec
 
 import (
-	"github.com/pkg/errors"
+	log "github.com/charmbracelet/log"
 	"github.com/samber/lo"
-	"github.com/spf13/cobra"
 
+	"github.com/cloudposse/atmos/internal/tui/templates/term"
 	cfg "github.com/cloudposse/atmos/pkg/config"
+	"github.com/cloudposse/atmos/pkg/pager"
 	"github.com/cloudposse/atmos/pkg/schema"
 	u "github.com/cloudposse/atmos/pkg/utils"
 )
 
-// ExecuteDescribeComponentCmd executes `describe component` command.
-func ExecuteDescribeComponentCmd(cmd *cobra.Command, args []string) error {
-	if len(args) != 1 {
-		return errors.New("invalid arguments. The command requires one argument `component`")
-	}
-
-	atmosConfig, err := cfg.InitCliConfig(schema.ConfigAndStacksInfo{}, true)
-	if err != nil {
-		return err
-	}
-
-	flags := cmd.Flags()
-
-	stack, err := flags.GetString("stack")
-	if err != nil {
-		return err
-	}
-
-	format, err := flags.GetString("format")
-	if err != nil {
-		return err
-	}
-
-	file, err := flags.GetString("file")
-	if err != nil {
-		return err
-	}
-
-	processTemplates, err := flags.GetBool("process-templates")
-	if err != nil {
-		return err
-	}
+type DescribeComponentParams struct {
+	Component            string
+	Stack                string
+	ProcessTemplates     bool
+	ProcessYamlFunctions bool
+	Skip                 []string
+	Query                string
+	Pager                string
+	Format               string
+	File                 string
+}
 
-	processYamlFunctions, err := flags.GetBool("process-functions")
-	if err != nil {
-		return err
-	}
+type DescribeComponentExec struct {
+	pageCreator              pager.PageCreator
+	printOrWriteToFile       func(atmosConfig *schema.AtmosConfiguration, format string, file string, data any) error
+	IsTTYSupportForStdout    func() bool
+	initCliConfig            func(configAndStacksInfo schema.ConfigAndStacksInfo, processStacks bool) (schema.AtmosConfiguration, error)
+	executeDescribeComponent func(component string, stack string, processTemplates bool, processYamlFunctions bool, skip []string) (map[string]any, error)
+	evaluateYqExpression     func(atmosConfig *schema.AtmosConfiguration, data any, yq string) (any, error)
+}
 
-	query, err := flags.GetString("query")
-	if err != nil {
-		return err
+func NewDescribeComponentExec() *DescribeComponentExec {
+	return &DescribeComponentExec{
+		printOrWriteToFile:       printOrWriteToFile,
+		IsTTYSupportForStdout:    term.IsTTYSupportForStdout,
+		pageCreator:              pager.New(),
+		initCliConfig:            cfg.InitCliConfig,
+		executeDescribeComponent: ExecuteDescribeComponent,
+		evaluateYqExpression:     u.EvaluateYqExpression,
 	}
+}
 
-	skip, err := flags.GetStringSlice("skip")
+func (d *DescribeComponentExec) ExecuteDescribeComponentCmd(describeComponentParams DescribeComponentParams) error {
+	component := describeComponentParams.Component
+	stack := describeComponentParams.Stack
+	processTemplates := describeComponentParams.ProcessTemplates
+	processYamlFunctions := describeComponentParams.ProcessYamlFunctions
+	skip := describeComponentParams.Skip
+	query := describeComponentParams.Query
+	pager := describeComponentParams.Pager
+	format := describeComponentParams.Format
+	file := describeComponentParams.File
+
+	var err error
+	var atmosConfig schema.AtmosConfiguration
+
+	atmosConfig, err = d.initCliConfig(schema.ConfigAndStacksInfo{
+		ComponentFromArg: component,
+		Stack:            stack,
+	}, true)
 	if err != nil {
 		return err
 	}
 
-	component := args[0]
-
-	componentSection, err := ExecuteDescribeComponent(
+	componentSection, err := d.executeDescribeComponent(
 		component,
 		stack,
 		processTemplates,
@@ -72,9 +77,12 @@ func ExecuteDescribeComponentCmd(cmd *cobra.Command, args []string) error {
 	}
 
 	var res any
+	if pager != "" {
+		atmosConfig.Settings.Terminal.Pager = pager
+	}
 
 	if query != "" {
-		res, err = u.EvaluateYqExpression(&atmosConfig, componentSection, query)
+		res, err = d.evaluateYqExpression(&atmosConfig, componentSection, query)
 		if err != nil {
 			return err
 		}
@@ -82,7 +90,19 @@ func ExecuteDescribeComponentCmd(cmd *cobra.Command, args []string) error {
 		res = componentSection
 	}
 
-	err = printOrWriteToFile(format, file, res)
+	if atmosConfig.Settings.Terminal.IsPagerEnabled() {
+		err = d.viewConfig(&atmosConfig, component, format, res)
+		switch err.(type) {
+		case DescribeConfigFormatError:
+			return err
+		case nil:
+			return nil
+		default:
+			log.Debug("Failed to use pager")
+		}
+	}
+
+	err = d.printOrWriteToFile(&atmosConfig, format, file, res)
 	if err != nil {
 		return err
 	}
@@ -90,6 +110,34 @@ func ExecuteDescribeComponentCmd(cmd *cobra.Command, args []string) error {
 	return nil
 }
 
+func (d *DescribeComponentExec) viewConfig(atmosConfig *schema.AtmosConfiguration, displayName string, format string, data any) error {
+	if !d.IsTTYSupportForStdout() {
+		return ErrTTYNotSupported
+	}
+	var content string
+	var err error
+	switch format {
+	case "yaml":
+		content, err = u.GetHighlightedYAML(atmosConfig, data)
+		if err != nil {
+			return err
+		}
+	case "json":
+		content, err = u.GetHighlightedJSON(atmosConfig, data)
+		if err != nil {
+			return err
+		}
+	default:
+		return DescribeConfigFormatError{
+			format,
+		}
+	}
+	if err := d.pageCreator.Run(displayName, content); err != nil {
+		return err
+	}
+	return nil
+}
+
 // ExecuteDescribeComponent describes component config
 func ExecuteDescribeComponent(
 	component string,
diff --git a/internal/exec/describe_component_test.go b/internal/exec/describe_component_test.go
new file mode 100644
index 0000000000..cb00c7a247
--- /dev/null
+++ b/internal/exec/describe_component_test.go
@@ -0,0 +1,125 @@
+package exec
+
+import (
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/stretchr/testify/assert"
+
+	"github.com/cloudposse/atmos/pkg/pager"
+	"github.com/cloudposse/atmos/pkg/schema"
+)
+
+// --- Test ---
+func TestExecuteDescribeComponentCmd_Success_YAMLWithPager(t *testing.T) {
+	mockedExec := &DescribeComponentExec{
+		printOrWriteToFile: func(atmosConfig *schema.AtmosConfiguration, format string, file string, data any) error {
+			return nil
+		},
+		IsTTYSupportForStdout: func() bool {
+			return true
+		},
+		executeDescribeComponent: func(component, stack string, processTemplates, processYamlFunctions bool, skip []string) (map[string]any, error) {
+			return map[string]any{
+				"component": component,
+				"stack":     stack,
+			}, nil
+		},
+		initCliConfig: func(configAndStacksInfo schema.ConfigAndStacksInfo, processStacks bool) (schema.AtmosConfiguration, error) {
+			return schema.AtmosConfiguration{}, nil
+		},
+		evaluateYqExpression: func(atmosConfig *schema.AtmosConfiguration, data any, yq string) (any, error) {
+			return data, nil
+		},
+	}
+
+	tests := []struct {
+		name          string
+		params        DescribeComponentParams
+		expectedError bool
+	}{
+		{
+			name: "Test pager with YAML format",
+			params: DescribeComponentParams{
+				Component: "component-1",
+				Stack:     "nonprod",
+				Pager:     "less",
+				Format:    "yaml",
+			},
+		},
+		{
+			name: "Test pager with JSON format",
+			params: DescribeComponentParams{
+				Component: "component-1",
+				Stack:     "nonprod",
+				Pager:     "less",
+				Format:    "json",
+			},
+		},
+		{
+			name: "Test no pager with YAML format",
+			params: DescribeComponentParams{
+				Component: "component-1",
+				Stack:     "nonprod",
+				Pager:     "more",
+				Format:    "yaml",
+			},
+		},
+		{
+			name: "Test no pager with JSON format",
+			params: DescribeComponentParams{
+				Component: "component-1",
+				Stack:     "nonprod",
+				Pager:     "more",
+				Format:    "json",
+			},
+		},
+		{
+			name: "Test invalid format",
+			params: DescribeComponentParams{
+				Component: "component-1",
+				Stack:     "nonprod",
+				Pager:     "less",
+				Format:    "invalid-format",
+			},
+			expectedError: true,
+		},
+		{
+			name: "Test pager with query",
+			params: DescribeComponentParams{
+				Component: "component-1",
+				Stack:     "nonprod",
+				Pager:     "less",
+				Format:    "json",
+				Query:     ".component",
+			},
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			if test.params.Pager == "less" && !test.expectedError {
+				ctrl := gomock.NewController(t)
+				pagerMock := pager.NewMockPageCreator(ctrl)
+				pagerMock.EXPECT().Run(gomock.Any(), gomock.Any()).Return(nil).Times(1)
+				mockedExec.pageCreator = pagerMock
+			} else {
+				mockedExec.printOrWriteToFile = func(atmosConfig *schema.AtmosConfiguration, format string, file string, data any) error {
+					assert.Equal(t, test.params.Format, format)
+					assert.Equal(t, "", file)
+					assert.Equal(t, map[string]any{
+						"component": "component-1",
+						"stack":     "nonprod",
+					}, data)
+					return nil
+				}
+			}
+			// stub out internal deps
+			err := mockedExec.ExecuteDescribeComponentCmd(test.params)
+			if test.expectedError {
+				assert.Error(t, err)
+			} else {
+				assert.NoError(t, err)
+			}
+		})
+	}
+}
diff --git a/internal/exec/describe_config.go b/internal/exec/describe_config.go
index fad3a68d9b..e2773b3503 100644
--- a/internal/exec/describe_config.go
+++ b/internal/exec/describe_config.go
@@ -26,7 +26,7 @@ var ErrTTYNotSupported = fmt.Errorf("tty not supported for this command")
 type describeConfigExec struct {
 	atmosConfig           *schema.AtmosConfiguration
 	pageCreator           pager.PageCreator
-	printOrWriteToFile    func(format string, file string, data any) error
+	printOrWriteToFile    func(atmosConfig *schema.AtmosConfiguration, format string, file string, data any) error
 	IsTTYSupportForStdout func() bool
 }
 
@@ -63,7 +63,7 @@ func (d *describeConfigExec) ExecuteDescribeConfigCmd(query, format, output stri
 			log.Debug("Failed to use pager")
 		}
 	}
-	return d.printOrWriteToFile(format, output, res)
+	return d.printOrWriteToFile(d.atmosConfig, format, output, res)
 }
 
 func (d *describeConfigExec) viewConfig(format string, data *schema.AtmosConfiguration) error {
@@ -74,12 +74,12 @@ func (d *describeConfigExec) viewConfig(format string, data *schema.AtmosConfigu
 	var err error
 	switch format {
 	case "yaml":
-		content, err = u.GetAtmosConfigYAML(data)
+		content, err = u.GetHighlightedYAML(data, data)
 		if err != nil {
 			return err
 		}
 	case "json":
-		content, err = u.GetAtmosConfigJSON(data)
+		content, err = u.GetHighlightedJSON(data, data)
 		if err != nil {
 			return err
 		}
diff --git a/internal/exec/describe_config_test.go b/internal/exec/describe_config_test.go
index 62931c244b..3dc2963fa6 100644
--- a/internal/exec/describe_config_test.go
+++ b/internal/exec/describe_config_test.go
@@ -87,7 +87,7 @@ func TestDescribeConfig(t *testing.T) {
 		dc := &describeConfigExec{
 			atmosConfig:           config,
 			IsTTYSupportForStdout: func() bool { return false },
-			printOrWriteToFile: func(format, file string, data any) error {
+			printOrWriteToFile: func(atmosConfig *schema.AtmosConfiguration, format, file string, data any) error {
 				assert.Equal(t, "yaml", format)
 				assert.Equal(t, "", file)
 				assert.Equal(t, config, data)
@@ -103,7 +103,7 @@ func TestDescribeConfig(t *testing.T) {
 		dc := &describeConfigExec{
 			atmosConfig:           config,
 			IsTTYSupportForStdout: func() bool { return false },
-			printOrWriteToFile: func(format, file string, data any) error {
+			printOrWriteToFile: func(atmosConfig *schema.AtmosConfiguration, format, file string, data any) error {
 				assert.Equal(t, "yaml", format)
 				assert.Equal(t, "", file)
 				assert.Equal(t, config, data)
diff --git a/internal/exec/describe_dependents.go b/internal/exec/describe_dependents.go
index c80a9dea0e..1b5fbfb3ca 100644
--- a/internal/exec/describe_dependents.go
+++ b/internal/exec/describe_dependents.go
@@ -76,7 +76,7 @@ func ExecuteDescribeDependentsCmd(cmd *cobra.Command, args []string) error {
 		res = dependents
 	}
 
-	err = printOrWriteToFile(format, file, res)
+	err = printOrWriteToFile(&atmosConfig, format, file, res)
 	if err != nil {
 		return err
 	}
diff --git a/internal/exec/describe_stacks.go b/internal/exec/describe_stacks.go
index 2188793448..0dcade90bd 100644
--- a/internal/exec/describe_stacks.go
+++ b/internal/exec/describe_stacks.go
@@ -136,7 +136,7 @@ func ExecuteDescribeStacksCmd(cmd *cobra.Command, args []string) error {
 		res = finalStacksMap
 	}
 
-	err = printOrWriteToFile(format, file, res)
+	err = printOrWriteToFile(&atmosConfig, format, file, res)
 	if err != nil {
 		return err
 	}
diff --git a/internal/exec/describe_workflows.go b/internal/exec/describe_workflows.go
index dc8eb1c7dd..a90c9f8697 100644
--- a/internal/exec/describe_workflows.go
+++ b/internal/exec/describe_workflows.go
@@ -76,7 +76,7 @@ func ExecuteDescribeWorkflowsCmd(cmd *cobra.Command, args []string) error {
 		}
 	}
 
-	err = printOrWriteToFile(format, "", res)
+	err = printOrWriteToFile(&atmosConfig, format, "", res)
 	if err != nil {
 		return err
 	}
diff --git a/internal/exec/file_utils.go b/internal/exec/file_utils.go
index 4df7264459..ed0063f2bd 100644
--- a/internal/exec/file_utils.go
+++ b/internal/exec/file_utils.go
@@ -32,6 +32,7 @@ func closeFile(fileName string, file io.ReadCloser) {
 // printOrWriteToFile takes the output format (`yaml` or `json`) and a file name,
 // and prints the data to the console or to a file (if file is specified)
 func printOrWriteToFile(
+	atmosConfig *schema.AtmosConfiguration,
 	format string,
 	file string,
 	data any,
@@ -39,7 +40,7 @@ func printOrWriteToFile(
 	switch format {
 	case "yaml":
 		if file == "" {
-			err := u.PrintAsYAML(data)
+			err := u.PrintAsYAML(atmosConfig, data)
 			if err != nil {
 				return err
 			}
@@ -52,7 +53,7 @@ func printOrWriteToFile(
 
 	case "json":
 		if file == "" {
-			err := u.PrintAsJSON(data)
+			err := u.PrintAsJSON(atmosConfig, data)
 			if err != nil {
 				return err
 			}
diff --git a/pkg/atlantis/atlantis_generate_repo_config_test.go b/pkg/atlantis/atlantis_generate_repo_config_test.go
index 13ed6e85ec..5d9e8cbfc7 100644
--- a/pkg/atlantis/atlantis_generate_repo_config_test.go
+++ b/pkg/atlantis/atlantis_generate_repo_config_test.go
@@ -15,7 +15,7 @@ func TestAtlantisGenerateRepoConfig(t *testing.T) {
 	atmosConfig, err := cfg.InitCliConfig(schema.ConfigAndStacksInfo{}, true)
 	assert.Nil(t, err)
 
-	err = u.PrintAsYAML(atmosConfig)
+	err = u.PrintAsYAML(&atmosConfig, atmosConfig)
 	assert.Nil(t, err)
 
 	atlantisConfig := atmosConfig.Integrations.Atlantis
@@ -37,7 +37,7 @@ func TestAtlantisGenerateRepoConfig(t *testing.T) {
 	atlantisYaml.AllowedRegexpPrefixes = configTemplate.AllowedRegexpPrefixes
 	atlantisYaml.Projects = []schema.AtlantisProjectConfig{projectTemplate}
 
-	err = u.PrintAsYAML(atlantisYaml)
+	err = u.PrintAsYAML(&atmosConfig, atlantisYaml)
 	assert.Nil(t, err)
 }
 
diff --git a/pkg/utils/highlight_utils.go b/pkg/utils/highlight_utils.go
index c51b5659d3..553c110b77 100644
--- a/pkg/utils/highlight_utils.go
+++ b/pkg/utils/highlight_utils.go
@@ -30,7 +30,7 @@ func DefaultHighlightSettings() *schema.SyntaxHighlighting {
 }
 
 // GetHighlightSettings returns the syntax highlighting settings from the config or defaults
-func GetHighlightSettings(config schema.AtmosConfiguration) *schema.SyntaxHighlighting {
+func GetHighlightSettings(config *schema.AtmosConfiguration) *schema.SyntaxHighlighting {
 	defaults := DefaultHighlightSettings()
 	if config.Settings.Terminal.SyntaxHighlighting == (schema.SyntaxHighlighting{}) {
 		return defaults
@@ -72,7 +72,7 @@ func HighlightCode(code string, lexerName string, theme string) (string, error)
 }
 
 // HighlightCodeWithConfig highlights the given code using the provided configuration
-func HighlightCodeWithConfig(code string, config schema.AtmosConfiguration, format ...string) (string, error) {
+func HighlightCodeWithConfig(config *schema.AtmosConfiguration, code string, format ...string) (string, error) {
 	if !term.IsTerminal(int(os.Stdout.Fd())) {
 		return code, nil
 	}
@@ -172,7 +172,7 @@ func NewHighlightWriter(w io.Writer, config schema.AtmosConfiguration, format ..
 // This maintains compatibility with the io.Writer interface contract while still
 // providing syntax highlighting functionality.
 func (h *HighlightWriter) Write(p []byte) (n int, err error) {
-	highlighted, err := HighlightCodeWithConfig(string(p), h.config, h.format)
+	highlighted, err := HighlightCodeWithConfig(&h.config, string(p), h.format)
 	if err != nil {
 		return 0, err
 	}
diff --git a/pkg/utils/json_utils.go b/pkg/utils/json_utils.go
index 4fae108329..c9216e3e28 100644
--- a/pkg/utils/json_utils.go
+++ b/pkg/utils/json_utils.go
@@ -12,27 +12,31 @@ import (
 )
 
 // PrintAsJSON prints the provided value as JSON document to the console
-func PrintAsJSON(data any) error {
-	j, err := ConvertToJSON(data)
+func PrintAsJSON(atmosConfig *schema.AtmosConfiguration, data any) error {
+	highlighted, err := GetHighlightedJSON(atmosConfig, data)
 	if err != nil {
 		return err
 	}
+	PrintMessage(highlighted)
+	return nil
+}
+
+func GetHighlightedJSON(atmosConfig *schema.AtmosConfiguration, data any) (string, error) {
+	j, err := ConvertToJSON(data)
+	if err != nil {
+		return "", err
+	}
 
 	var prettyJSON bytes.Buffer
 	err = json.Indent(&prettyJSON, []byte(j), "", "  ")
 	if err != nil {
-		return err
+		return "", err
 	}
-
-	atmosConfig := ExtractAtmosConfig(data)
-	highlighted, err := HighlightCodeWithConfig(prettyJSON.String(), atmosConfig)
+	highlighted, err := HighlightCodeWithConfig(atmosConfig, prettyJSON.String())
 	if err != nil {
-		// Fallback to plain text if highlighting fails
-		PrintMessage(prettyJSON.String())
-		return nil
+		return prettyJSON.String(), nil
 	}
-	PrintMessage(highlighted)
-	return nil
+	return highlighted, nil
 }
 
 func GetAtmosConfigJSON(atmosConfig *schema.AtmosConfiguration) (string, error) {
@@ -47,7 +51,7 @@ func GetAtmosConfigJSON(atmosConfig *schema.AtmosConfiguration) (string, error)
 		return "", err
 	}
 
-	highlighted, err := HighlightCodeWithConfig(prettyJSON.String(), *atmosConfig)
+	highlighted, err := HighlightCodeWithConfig(atmosConfig, prettyJSON.String())
 	if err == nil {
 		return highlighted, nil
 	}
diff --git a/pkg/utils/json_utils_test.go b/pkg/utils/json_utils_test.go
new file mode 100644
index 0000000000..2d85d3a2fc
--- /dev/null
+++ b/pkg/utils/json_utils_test.go
@@ -0,0 +1,33 @@
+package utils
+
+import (
+	"testing"
+
+	"github.com/cloudposse/atmos/pkg/schema"
+)
+
+func TestPrintAsJson(t *testing.T) {
+	atmosConfig := &schema.AtmosConfiguration{
+		Settings: schema.AtmosSettings{
+			Terminal: schema.Terminal{
+				SyntaxHighlighting: schema.SyntaxHighlighting{
+					Enabled:                true,
+					Formatter:              "terminal",
+					Theme:                  "dracula",
+					HighlightedOutputPager: true,
+					LineNumbers:            true,
+					Wrap:                   false,
+				},
+			},
+		},
+	}
+
+	data := map[string]any{
+		"key": "value",
+	}
+
+	err := PrintAsJSON(atmosConfig, data)
+	if err != nil {
+		t.Fatalf("expected no error, got %v", err)
+	}
+}
diff --git a/pkg/utils/yaml_utils.go b/pkg/utils/yaml_utils.go
index bbbb82d36e..bed01c89cc 100644
--- a/pkg/utils/yaml_utils.go
+++ b/pkg/utils/yaml_utils.go
@@ -41,8 +41,8 @@ var (
 )
 
 // PrintAsYAML prints the provided value as YAML document to the console
-func PrintAsYAML(data any) error {
-	y, err := GetAtmosConfigYAML(data)
+func PrintAsYAML(atmosConfig *schema.AtmosConfiguration, data any) error {
+	y, err := GetHighlightedYAML(atmosConfig, data)
 	if err != nil {
 		return err
 	}
@@ -50,13 +50,12 @@ func PrintAsYAML(data any) error {
 	return nil
 }
 
-func GetAtmosConfigYAML(data any) (string, error) {
+func GetHighlightedYAML(atmosConfig *schema.AtmosConfiguration, data any) (string, error) {
 	y, err := ConvertToYAML(data)
 	if err != nil {
 		return "", err
 	}
-	atmosConfig := ExtractAtmosConfig(data)
-	highlighted, err := HighlightCodeWithConfig(y, atmosConfig)
+	highlighted, err := HighlightCodeWithConfig(atmosConfig, y)
 	if err != nil {
 		return y, err
 	}
diff --git a/pkg/utils/yq_test.go b/pkg/utils/yq_test.go
index 11a7afe620..7feb7d7156 100644
--- a/pkg/utils/yq_test.go
+++ b/pkg/utils/yq_test.go
@@ -65,7 +65,7 @@ vars:
 	assert.Nil(t, err)
 	assert.NotNil(t, res)
 	assert.Equal(t, true, res)
-	err = PrintAsYAML(res)
+	err = PrintAsYAML(atmosConfig, res)
 	assert.Nil(t, err)
 
 	yq = ".settings.mode"
@@ -73,7 +73,7 @@ vars:
 	assert.Nil(t, err)
 	assert.NotNil(t, res)
 	assert.Equal(t, "test", res)
-	err = PrintAsYAML(res)
+	err = PrintAsYAML(atmosConfig, res)
 	assert.Nil(t, err)
 
 	yq = ".vars.tags.atmos_component"
@@ -81,7 +81,7 @@ vars:
 	assert.Nil(t, err)
 	assert.NotNil(t, res)
 	assert.Equal(t, "vpc", res)
-	err = PrintAsYAML(res)
+	err = PrintAsYAML(atmosConfig, res)
 	assert.Nil(t, err)
 
 	yq = ".vars.availability_zones.0"
@@ -89,7 +89,7 @@ vars:
 	assert.Nil(t, err)
 	assert.NotNil(t, res)
 	assert.Equal(t, "us-east-2a", res)
-	err = PrintAsYAML(res)
+	err = PrintAsYAML(atmosConfig, res)
 	assert.Nil(t, err)
 
 	yq = ".vars.ipv4_primary_cidr_block"
@@ -97,7 +97,7 @@ vars:
 	assert.Nil(t, err)
 	assert.NotNil(t, res)
 	assert.Equal(t, "10.8.0.0/18", res)
-	err = PrintAsYAML(res)
+	err = PrintAsYAML(atmosConfig, res)
 	assert.Nil(t, err)
 
 	yq = ".vars.enabled"
@@ -105,7 +105,7 @@ vars:
 	assert.Nil(t, err)
 	assert.NotNil(t, res)
 	assert.Equal(t, true, res)
-	err = PrintAsYAML(res)
+	err = PrintAsYAML(atmosConfig, res)
 	assert.Nil(t, err)
 
 	yq = ".vars.enabled = false"
@@ -117,7 +117,7 @@ vars:
 	assert.Nil(t, err)
 	assert.NotNil(t, res)
 	assert.Equal(t, false, res)
-	err = PrintAsYAML(res)
+	err = PrintAsYAML(atmosConfig, res)
 	assert.Nil(t, err)
 
 	yq = ".vars.ipv4_primary_cidr_block = \"10.8.8.0/20\""
@@ -129,7 +129,7 @@ vars:
 	assert.Nil(t, err)
 	assert.NotNil(t, res)
 	assert.Equal(t, "10.8.8.0/20", res)
-	err = PrintAsYAML(res)
+	err = PrintAsYAML(atmosConfig, res)
 	assert.Nil(t, err)
 
 	yq = ".vars.availability_zones.0 = \"us-east-2d\""
@@ -141,7 +141,7 @@ vars:
 	assert.Nil(t, err)
 	assert.NotNil(t, res)
 	assert.Equal(t, "us-east-2d", res)
-	err = PrintAsYAML(res)
+	err = PrintAsYAML(atmosConfig, res)
 	assert.Nil(t, err)
 
 	yq = ".vars.enabled = false | .vars.tags.terraform_workspace = \"plat-ue2-prod-override\" | .vars.max_subnet_count = 2 | .settings.test = false"
@@ -152,25 +152,25 @@ vars:
 	res1, err := EvaluateYqExpression(atmosConfig, res, yq)
 	assert.Nil(t, err)
 	assert.Equal(t, false, res1)
-	err = PrintAsYAML(res1)
+	err = PrintAsYAML(atmosConfig, res1)
 	assert.Nil(t, err)
 	yq = ".vars.tags.terraform_workspace"
 	res2, err := EvaluateYqExpression(atmosConfig, res, yq)
 	assert.Nil(t, err)
 	assert.Equal(t, "plat-ue2-prod-override", res2)
-	err = PrintAsYAML(res2)
+	err = PrintAsYAML(atmosConfig, res2)
 	assert.Nil(t, err)
 	yq = ".vars.max_subnet_count"
 	res3, err := EvaluateYqExpression(atmosConfig, res, yq)
 	assert.Nil(t, err)
 	assert.Equal(t, 2, res3)
-	err = PrintAsYAML(res3)
+	err = PrintAsYAML(atmosConfig, res3)
 	assert.Nil(t, err)
 	yq = ".settings.test"
 	res4, err := EvaluateYqExpression(atmosConfig, res, yq)
 	assert.Nil(t, err)
 	assert.Equal(t, false, res4)
-	err = PrintAsYAML(res4)
+	err = PrintAsYAML(atmosConfig, res4)
 	assert.Nil(t, err)
 }
 
diff --git a/tests/cli_describe_component_test.go b/tests/cli_describe_component_test.go
new file mode 100644
index 0000000000..6f6a0c63ec
--- /dev/null
+++ b/tests/cli_describe_component_test.go
@@ -0,0 +1,18 @@
+package tests
+
+import (
+	"os"
+	"testing"
+
+	"github.com/cloudposse/atmos/cmd"
+)
+
+func TestExecuteDescribeComponentCmd_Success_YAMLWithPager(t *testing.T) {
+	t.Chdir("./fixtures/scenarios/atmos-include-yaml-function")
+	oldArgs := os.Args
+	defer func() { os.Args = oldArgs }()
+	os.Args = []string{"atmos", "describe", "component", "component-1", "--stack", "nonprod", "--pager", "more", "--format", "yaml"}
+	if err := cmd.Execute(); err != nil {
+		t.Fatalf("failed to execute command: %v", err)
+	}
+}
diff --git a/tests/describe_test.go b/tests/describe_test.go
new file mode 100644
index 0000000000..75269d51e8
--- /dev/null
+++ b/tests/describe_test.go
@@ -0,0 +1,48 @@
+package tests
+
+import (
+	"os"
+	"testing"
+
+	"github.com/cloudposse/atmos/cmd"
+)
+
+func ExecuteCommand(args []string) error {
+	// Set the command line arguments
+	os.Args = args
+
+	// Execute the command
+	return cmd.Execute()
+}
+
+func TestDescribeComponentJSON(t *testing.T) {
+	// Set up the environment variables
+	currentWd, _ := os.Getwd()
+	defer os.Chdir(currentWd)
+	os.Chdir("./fixtures/scenarios/atmos-providers-section")
+
+	t.Setenv("ATMOS_PAGER", "more")
+
+	// Execute the command
+	os.Args = []string{"atmos", "describe", "component", "component-1", "--stack", "nonprod", "--format", "json"}
+	err := cmd.Execute()
+	if err != nil {
+		t.Fatalf("Failed to execute command: %v", err)
+	}
+}
+
+func TestDescribeComponentYAML(t *testing.T) {
+	// Set up the environment variables
+	currentWd, _ := os.Getwd()
+	defer os.Chdir(currentWd)
+	os.Chdir("./fixtures/scenarios/atmos-providers-section")
+
+	t.Setenv("ATMOS_PAGER", "more")
+
+	// Execute the command
+	os.Args = []string{"atmos", "describe", "component", "component-1", "--stack", "nonprod", "--format", "yaml"}
+	err := cmd.Execute()
+	if err != nil {
+		t.Fatalf("Failed to execute command: %v", err)
+	}
+}
diff --git a/website/docs/cli/commands/describe/describe-component.mdx b/website/docs/cli/commands/describe/describe-component.mdx
index 9a088d4512..33f0c82e3f 100644
--- a/website/docs/cli/commands/describe/describe-component.mdx
+++ b/website/docs/cli/commands/describe/describe-component.mdx
@@ -55,6 +55,8 @@ atmos describe component vpc -s tenant1-ue2-dev --skip=include,eval
 atmos describe component vpc -s plat-ue2-prod --query .vars.tags
 
 atmos describe component vpc -s plat-ue2-prod -q .settings
+
+atmos describe component vpc -s plat-ue2-prod --pager=more
 ```
 
 ## Arguments
@@ -74,6 +76,7 @@ atmos describe component vpc -s plat-ue2-prod -q .settings
 | `--process-functions` | Enable/disable processing of all Atmos YAML functions<br/>in Atmos stacks manifests when executing the command.<br/>Use the flag to see the component configuration<br/>before and after the functions are processed.<br/>If the flag is not provided, it's set to `true` by default.<br/>`atmos describe component <c> -s <stack> --process-functions=false`                               |       | no       |
 | `--skip`              | Skip processing a specific Atmos YAML function<br/>in Atmos stacks manifests when executing the command.<br/>To specify more than one function,<br/>use multiple `--skip` flags, or separate the functions with a comma:<br/>`atmos describe component <c> -s <stack> --skip=terraform.output --skip=include`<br/>`atmos describe component <c> -s <stack> --skip=terraform.output,include` |       | no       |
 | `--query`             | Query the results of the command using `yq` expressions.<br/><br/>`atmos describe component <c> -s <stack> --query .vars.tags`<br/><br/>For more details, refer to https://mikefarah.gitbook.io/yq                                                                                                                                                                                          | `-q`  | no       |
+| `--pager`             | Disable/Enable the paging user experience                                                                                                                                                                                                                                                                                                                                                   |       |          |
 
 ## Output
 


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 8**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>pkg/utils/highlight_utils.go (1)</summary><blockquote>

`84-85`: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Be careful with side effects in highlighting function.**

The function modifies `config.Settings.Terminal.MaxWidth` which is a side effect not obviously related to highlighting. Consider moving this to a more appropriate place or documenting it.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check if this field is modified elsewhere in similar contexts
rg "config\.Settings\.Terminal\.MaxWidth =" --type go
```

Length of output: 150

---



</details>

**Avoid unexpected side effects in highlight utility**

The call to  
```go
config.Settings.Terminal.MaxWidth = templates.GetTerminalWidth()
```  
in `pkg/utils/highlight_utils.go` (lines 84–85) modifies a global setting from within a formatting helper. This side effect isn’t obvious from the function’s responsibility.

• Move this assignment out of the highlight utility into your application’s startup or configuration initialization.  
• Or, if it must remain here, document in the function’s GoDoc that it alters `config.Settings.Terminal.MaxWidth`.

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (16)</summary><blockquote>

<details>
<summary>website/docs/cli/commands/describe/describe-component.mdx (1)</summary><blockquote>

`79-79`: **Clear documentation for the pager flag.**

The flag description accurately explains the purpose of the `--pager` flag. However, it might be helpful to mention the default value and supported values for complete user understanding.

Consider enhancing the description to include the default pager used and possible values:

```diff
-| `--pager`             | Disable/Enable the paging user experience                                                                                                                                                                                                                                                   |       |          |
+| `--pager`             | Disable/Enable the paging user experience. Use values like "less", "more", or "off" to control paging behavior. Default is "less".                                                                                                                                                           |       |          |
```

</blockquote></details>
<details>
<summary>pkg/schema/schema.go (1)</summary><blockquote>

`197-199`: **Added helper method to determine if pager is enabled.**

Good implementation that maintains backward compatibility while supporting more flexible configuration. The method considers various common string values that might indicate enablement.


Consider adding a check for "off" and other negation values for clarity:

```diff
func (t *Terminal) IsPagerEnabled() bool {
-	return t.Pager == "" || t.Pager == "on" || t.Pager == "less" || t.Pager == "true" || t.Pager == "yes" || t.Pager == "y" || t.Pager == "1"
+	// Check for empty value or positive indicators
+	if t.Pager == "" || t.Pager == "on" || t.Pager == "less" || t.Pager == "true" || t.Pager == "yes" || t.Pager == "y" || t.Pager == "1" {
+		return true
+	}
+	// Explicit checks for disabled values
+	if t.Pager == "off" || t.Pager == "false" || t.Pager == "no" || t.Pager == "n" || t.Pager == "0" {
+		return false
+	}
+	// Default to enabled if a pager name is provided
+	return t.Pager != ""
}
```

</blockquote></details>
<details>
<summary>pkg/utils/yq_utils.go (1)</summary><blockquote>

`82-116`: **Added type-safe evaluation function using generics.**

This well-implemented generic function improves type safety when evaluating yq expressions, eliminating the need for type assertions in consumer code. The function follows the same structure as the existing function with proper error handling and clear error messages.


Consider extracting the common YAML preferences setup to a helper function since it's duplicated between this function and `EvaluateYqExpression`:

```diff
+func getYqPreferences() yqlib.YamlPreferences {
+	return yqlib.YamlPreferences{
+		Indent:                      2,
+		ColorsEnabled:               false,
+		LeadingContentPreProcessing: true,
+		PrintDocSeparators:          true,
+		UnwrapScalar:                true,
+		EvaluateTogether:            false,
+	}
+}

 func EvaluateYqExpression(atmosConfig *schema.AtmosConfiguration, data any, yq string) (any, error) {
     // ...
-    pref := yqlib.YamlPreferences{
-        Indent:                      2,
-        ColorsEnabled:               false,
-        LeadingContentPreProcessing: true,
-        PrintDocSeparators:          true,
-        UnwrapScalar:                true,
-        EvaluateTogether:            false,
-    }
+    pref := getYqPreferences()
     // ...
 }

 func EvaluateYqExpressionWithType[T any](atmosConfig *schema.AtmosConfiguration, data T, yq string) (*T, error) {
     // ...
-    pref := yqlib.YamlPreferences{
-        Indent:                      2,
-        ColorsEnabled:               false,
-        LeadingContentPreProcessing: true,
-        PrintDocSeparators:          true,
-        UnwrapScalar:                true,
-        EvaluateTogether:            false,
-    }
+    pref := getYqPreferences()
     // ...
 }
```

</blockquote></details>
<details>
<summary>tests/describe_test.go (2)</summary><blockquote>

`10-16`: **This helper function isn't used in tests below**

The `ExecuteCommand` helper function is defined but not used in the test functions that follow. Consider using this function in your tests or removing it if not needed.


```diff
- func ExecuteCommand(args []string) error {
-	// Set the command line arguments
-	os.Args = args
-
-	// Execute the command
-	return cmd.Execute()
-}

func TestDescribeComponentJSON(t *testing.T) {
```

---

`34-48`: **Duplicate test structure could be refactored**

This test has very similar structure to `TestDescribeComponentJSON`. Consider creating a table-driven test or a test helper to reduce duplication.


```diff
+func testDescribeComponent(t *testing.T, format string) {
+	// Set up the environment variables
+	currentWd, _ := os.Getwd()
+	defer os.Chdir(currentWd)
+	os.Chdir("./fixtures/scenarios/atmos-providers-section")
+
+	t.Setenv("ATMOS_PAGER", "more")
+
+	// Execute the command
+	os.Args = []string{"atmos", "describe", "component", "component-1", "--stack", "nonprod", "--format", format}
+	err := cmd.Execute()
+	if err != nil {
+		t.Fatalf("Failed to execute command: %v", err)
+	}
+}
+
+func TestDescribeComponentJSON(t *testing.T) {
+	testDescribeComponent(t, "json")
+}
+
+func TestDescribeComponentYAML(t *testing.T) {
+	testDescribeComponent(t, "yaml")
+}
-func TestDescribeComponentYAML(t *testing.T) {
-	// Set up the environment variables
-	currentWd, _ := os.Getwd()
-	defer os.Chdir(currentWd)
-	os.Chdir("./fixtures/scenarios/atmos-providers-section")
-
-	t.Setenv("ATMOS_PAGER", "more")
-
-	// Execute the command
-	os.Args = []string{"atmos", "describe", "component", "component-1", "--stack", "nonprod", "--format", "yaml"}
-	err := cmd.Execute()
-	if err != nil {
-		t.Fatalf("Failed to execute command: %v", err)
-	}
-}
```

</blockquote></details>
<details>
<summary>internal/exec/describe_component_test.go (1)</summary><blockquote>

`98-124`: **Consider testing behavior when pager returns an error**

The test mocks the pager to return nil, but doesn't test how the code handles when the pager returns an error. Consider adding a test case for this scenario.


```diff
tests := []struct {
	name          string
	params        DescribeComponentParams
	expectedError bool
+	pagerError    bool
}{
	// existing test cases...
+	{
+		name: "Test pager with error",
+		params: DescribeComponentParams{
+			Component: "component-1",
+			Stack:     "nonprod",
+			Pager:     "less",
+			Format:    "yaml",
+		},
+		pagerError:    true,
+		expectedError: true,
+	},
}

for _, test := range tests {
	t.Run(test.name, func(t *testing.T) {
		if test.params.Pager == "less" && !test.expectedError {
			ctrl := gomock.NewController(t)
			pagerMock := pager.NewMockPageCreator(ctrl)
-			pagerMock.EXPECT().Run(gomock.Any(), gomock.Any()).Return(nil).Times(1)
+			var returnErr error
+			if test.pagerError {
+				returnErr = errors.New("pager error")
+			}
+			pagerMock.EXPECT().Run(gomock.Any(), gomock.Any()).Return(returnErr).Times(1)
			mockedExec.pageCreator = pagerMock
		} else {
			// existing code...
		}
```

</blockquote></details>
<details>
<summary>pkg/pager/model_test.go (1)</summary><blockquote>

`134-148`: **There's an assertion comment error in the B_Greater test case.**

The assertion comment in the B_Greater test case doesn't match the expected result.

```diff
-		assert.Equal(t, 5, result, "max(3, 5) should return 3")
+		assert.Equal(t, 5, result, "max(3, 5) should return 5")
```

</blockquote></details>
<details>
<summary>cmd/describe_component.go (1)</summary><blockquote>

`23-25`: **Redundant argument validation.**

This manual argument length check is unnecessary since `cobra.ExactArgs(1)` already enforces this constraint. Cobra will handle this validation before reaching this code.

```diff
-		if len(args) != 1 {
-			return errors.New("invalid arguments. The command requires one argument `component`")
-		}
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 24-25: cmd/describe_component.go#L24-L25
Added lines #L24 - L25 were not covered by tests

</details>

</details>

</blockquote></details>
<details>
<summary>pkg/utils/json_utils.go (1)</summary><blockquote>

`42-60`: **Consider consolidating duplicate JSON handling logic.**

There's significant overlap between `GetHighlightedJSON` and `GetAtmosConfigJSON`. Consider refactoring to avoid duplication.

```diff
-func GetAtmosConfigJSON(atmosConfig *schema.AtmosConfiguration) (string, error) {
-	j, err := ConvertToJSON(atmosConfig)
-	if err != nil {
-		return "", err
-	}
-
-	var prettyJSON bytes.Buffer
-	err = json.Indent(&prettyJSON, []byte(j), "", "  ")
-	if err != nil {
-		return "", err
-	}
-
-	highlighted, err := HighlightCodeWithConfig(atmosConfig, prettyJSON.String())
-	if err == nil {
-		return highlighted, nil
-	}
-	// Fallback to plain text if highlighting fails
-	return prettyJSON.String(), nil
+func GetAtmosConfigJSON(atmosConfig *schema.AtmosConfiguration) (string, error) {
+	return GetHighlightedJSON(atmosConfig, atmosConfig)
}
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 54-54: pkg/utils/json_utils.go#L54
Added line #L54 was not covered by tests

</details>

</details>

</blockquote></details>
<details>
<summary>internal/exec/describe_config_test.go (1)</summary><blockquote>

`17-127`: **Consider adding a test for pager failure handling.**

The tests cover most paths but don't test the case where the pager fails and falls back to direct printing.

Add a test case like:

```go
t.Run("ExecuteDescribeConfigCmd_PagerFailure_Fallback", func(t *testing.T) {
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()
    
    mockPager := pager.NewMockPageCreator(ctrl)
    mockPager.EXPECT().Run(describeConfigTitle, gomock.Any()).Return(fmt.Errorf("pager failed"))
    
    printCalled := false
    dc := &describeConfigExec{
        atmosConfig:           config,
        pageCreator:           mockPager,
        IsTTYSupportForStdout: func() bool { return true },
        printOrWriteToFile: func(atmosConfig *schema.AtmosConfiguration, format, file string, data any) error {
            printCalled = true
            return nil
        },
    }
    
    err := dc.ExecuteDescribeConfigCmd("", "yaml", "")
    assert.NoError(t, err)
    assert.True(t, printCalled, "PrintOrWriteToFile should be called as fallback")
})
```

</blockquote></details>
<details>
<summary>internal/exec/describe_config.go (2)</summary><blockquote>

`55-65`: **Consider more explicit error handling for log message.**

The "Failed to use pager" log message doesn't include the actual error, which would be helpful for debugging.

```diff
-			log.Debug("Failed to use pager")
+			log.Debug("Failed to use pager", "error", err)
```

---

`76-91`: **Consider consolidating similar code patterns.**

The YAML and JSON handling paths are nearly identical and could be refactored to reduce duplication.

```diff
-	switch format {
-	case "yaml":
-		content, err = u.GetHighlightedYAML(data, data)
-		if err != nil {
-			return err
-		}
-	case "json":
-		content, err = u.GetHighlightedJSON(data, data)
-		if err != nil {
-			return err
-		}
-	default:
-		return DescribeConfigFormatError{
-			format,
-		}
-	}
+	switch format {
+	case "yaml", "json":
+		if format == "yaml" {
+			content, err = u.GetHighlightedYAML(data, data)
+		} else {
+			content, err = u.GetHighlightedJSON(data, data)
+		}
+		if err != nil {
+			return err
+		}
+	default:
+		return DescribeConfigFormatError{format}
+	}
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 79-80: internal/exec/describe_config.go#L79-L80
Added lines #L79 - L80 were not covered by tests

---

[warning] 84-85: internal/exec/describe_config.go#L84-L85
Added lines #L84 - L85 were not covered by tests

</details>

</details>

</blockquote></details>
<details>
<summary>internal/exec/describe_component.go (3)</summary><blockquote>

`53-54`: **Rename local `pager` variable to avoid shadowing the imported package**

`pager := describeComponentParams.Pager` hides the `github.com/cloudposse/atmos/pkg/pager` import inside this method.  
Nothing breaks here, but the shadowing makes grepping harder and may mis-lead future readers.



```diff
-	pager := describeComponentParams.Pager
+	userPager := describeComponentParams.Pager
```

---

`93-101`: **Don’t swallow unexpected pager errors—bubble them up**

If `viewConfig` returns an error that isn’t a format problem, we only `log.Debug` and silently fall back to printing.  
Losing the original error makes troubleshooting tougher.



```diff
-		default:
-			log.Debug("Failed to use pager")
+		default:
+			log.Debug("Failed to use pager", "err", err)
+			return err
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 100-101: internal/exec/describe_component.go#L100-L101
Added lines #L100 - L101 were not covered by tests

</details>

</details>

---

`119-134`: **Provide a sane default when `format` is empty**

With the pager enabled and `--format` omitted, users immediately get
`DescribeConfigFormatError`.  Defaulting to YAML keeps behaviour aligned
with the non-pager path.



```diff
-	switch format {
-	case "yaml":
+	if format == "" {
+		format = "yaml"
+	}
+
+	switch format {
+	case "yaml":
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 123-124: internal/exec/describe_component.go#L123-L124
Added lines #L123 - L124 were not covered by tests

---

[warning] 128-129: internal/exec/describe_component.go#L128-L129
Added lines #L128 - L129 were not covered by tests

</details>

</details>

</blockquote></details>
<details>
<summary>pkg/pager/model.go (1)</summary><blockquote>

`191-197`: **Check error from `termenv.Copy` for completeness**

`termenv.Copy` can fail (e.g. when OSC 52 is unsupported).  
We already handle the clipboard library’s error; wrapping both in the same
check keeps feedback consistent.



```diff
-		// Copy using OSC 52
-		termenv.Copy(StripANSI(m.content))
-		if err := clipboard.WriteAll(StripANSI(m.content)); err != nil {
+		if err := termenv.Copy(StripANSI(m.content)); err != nil {
+			cmds = append(cmds, m.showStatusMessage(pagerStatusMessage{"Failed to copy to clipboard", true}))
+		} else if err := clipboard.WriteAll(StripANSI(m.content)); err != nil {
 			cmds = append(cmds, m.showStatusMessage(pagerStatusMessage{"Failed to copy to clipboard", true}))
 		} else {
 			cmds = append(cmds, m.showStatusMessage(pagerStatusMessage{"Copied contents", false}))
 		}
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: .coderabbit.yaml**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 2325ab9bc56ba1099e2681e520255aec85f6aabe and 8e46da4ce69139250ab666c11bf3670993a4a41f.

</details>

<details>
<summary>📒 Files selected for processing (42)</summary>

* `Makefile` (1 hunks)
* `cmd/describe.go` (1 hunks)
* `cmd/describe_component.go` (3 hunks)
* `cmd/describe_config.go` (2 hunks)
* `cmd/docs.go` (1 hunks)
* `go.mod` (2 hunks)
* `internal/exec/atlantis_generate_repo_config.go` (1 hunks)
* `internal/exec/atmos.go` (2 hunks)
* `internal/exec/describe_affected.go` (3 hunks)
* `internal/exec/describe_component.go` (2 hunks)
* `internal/exec/describe_component_test.go` (1 hunks)
* `internal/exec/describe_config.go` (1 hunks)
* `internal/exec/describe_config_test.go` (1 hunks)
* `internal/exec/describe_dependents.go` (1 hunks)
* `internal/exec/describe_stacks.go` (1 hunks)
* `internal/exec/describe_workflows.go` (1 hunks)
* `internal/exec/file_utils.go` (2 hunks)
* `pkg/atlantis/atlantis_generate_repo_config_test.go` (2 hunks)
* `pkg/config/default.go` (1 hunks)
* `pkg/config/load.go` (2 hunks)
* `pkg/pager/mock_pager.go` (1 hunks)
* `pkg/pager/model.go` (1 hunks)
* `pkg/pager/model_test.go` (1 hunks)
* `pkg/pager/pager.go` (1 hunks)
* `pkg/schema/schema.go` (1 hunks)
* `pkg/schema/schema_test.go` (1 hunks)
* `pkg/utils/highlight_utils.go` (3 hunks)
* `pkg/utils/json_utils.go` (1 hunks)
* `pkg/utils/json_utils_test.go` (1 hunks)
* `pkg/utils/yaml_utils.go` (1 hunks)
* `pkg/utils/yq_test.go` (5 hunks)
* `pkg/utils/yq_utils.go` (1 hunks)
* `tests/cli_describe_component_test.go` (1 hunks)
* `tests/describe_test.go` (1 hunks)
* `tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden` (1 hunks)
* `tests/snapshots/TestCLICommands_atmos_describe_config_-f_yaml.stdout.golden` (1 hunks)
* `tests/snapshots/TestCLICommands_atmos_describe_config_imports.stderr.golden` (1 hunks)
* `tests/snapshots/TestCLICommands_atmos_describe_config_imports.stdout.golden` (1 hunks)
* `tests/snapshots/TestCLICommands_atmos_describe_configuration.stderr.golden` (1 hunks)
* `tests/snapshots/TestCLICommands_atmos_describe_configuration.stdout.golden` (1 hunks)
* `tests/test-cases/demo-stacks.yaml` (3 hunks)
* `website/docs/cli/commands/describe/describe-component.mdx` (2 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧠 Learnings (3)</summary>

<details>
<summary>cmd/docs.go (1)</summary>

```
Learnt from: RoseSecurity
PR: cloudposse/atmos#848
File: pkg/utils/doc_utils.go:19-22
Timestamp: 2024-12-12T17:13:53.409Z
Learning: In `pkg/utils/doc_utils.go`, the `DisplayDocs` function uses the `PAGER` environment variable, which is intentionally user-configurable to allow users to specify custom pager commands that fit their workflow; adding validation to restrict it is not desired.
```

</details>
<details>
<summary>pkg/config/load.go (1)</summary>

```
Learnt from: osterman
PR: cloudposse/atmos#1202
File: pkg/utils/yaml_func_exec.go:104-104
Timestamp: 2025-04-23T15:02:50.246Z
Learning: In the Atmos codebase, direct calls to `os.Getenv` should be avoided. Instead, use `viper.BindEnv` for environment variable access. This provides a consistent approach to configuration management across the codebase.
```

</details>
<details>
<summary>internal/exec/describe_stacks.go (1)</summary>

```
Learnt from: Cerebrovinny
PR: cloudposse/atmos#764
File: internal/exec/describe_stacks.go:289-295
Timestamp: 2024-11-13T21:37:07.852Z
Learning: In the `internal/exec/describe_stacks.go` file of the `atmos` project written in Go, avoid extracting the stack name handling logic into a helper function within the `ExecuteDescribeStacks` method, even if the logic appears duplicated.
```

</details>

</details><details>
<summary>🧬 Code Graph Analysis (8)</summary>

<details>
<summary>pkg/atlantis/atlantis_generate_repo_config_test.go (1)</summary><blockquote>

<details>
<summary>pkg/utils/yaml_utils.go (1)</summary>

* `PrintAsYAML` (44-51)

</details>

</blockquote></details>
<details>
<summary>internal/exec/atlantis_generate_repo_config.go (1)</summary><blockquote>

<details>
<summary>pkg/utils/yaml_utils.go (1)</summary>

* `PrintAsYAML` (44-51)

</details>

</blockquote></details>
<details>
<summary>internal/exec/file_utils.go (3)</summary><blockquote>

<details>
<summary>pkg/schema/schema.go (1)</summary>

* `AtmosConfiguration` (13-45)

</details>
<details>
<summary>pkg/utils/yaml_utils.go (1)</summary>

* `PrintAsYAML` (44-51)

</details>
<details>
<summary>pkg/utils/json_utils.go (1)</summary>

* `PrintAsJSON` (15-22)

</details>

</blockquote></details>
<details>
<summary>internal/exec/atmos.go (1)</summary><blockquote>

<details>
<summary>pkg/utils/yaml_utils.go (1)</summary>

* `PrintAsYAML` (44-51)

</details>

</blockquote></details>
<details>
<summary>pkg/schema/schema_test.go (1)</summary><blockquote>

<details>
<summary>pkg/schema/schema.go (1)</summary>

* `Terminal` (189-195)

</details>

</blockquote></details>
<details>
<summary>pkg/utils/yq_utils.go (2)</summary><blockquote>

<details>
<summary>pkg/schema/schema.go (1)</summary>

* `AtmosConfiguration` (13-45)

</details>
<details>
<summary>pkg/utils/yaml_utils.go (2)</summary>

* `ConvertToYAML` (89-95)
* `UnmarshalYAML` (222-224)

</details>

</blockquote></details>
<details>
<summary>cmd/describe_component.go (3)</summary><blockquote>

<details>
<summary>internal/exec/describe_component.go (2)</summary>

* `NewDescribeComponentExec` (35-44)
* `DescribeComponentParams` (14-24)

</details>
<details>
<summary>pkg/utils/markdown_utils.go (1)</summary>

* `PrintErrorMarkdownAndExit` (87-89)

</details>
<details>
<summary>cmd/cmd_utils.go (2)</summary>

* `ComponentsArgCompletion` (755-777)
* `AddStackCompletion` (748-753)

</details>

</blockquote></details>
<details>
<summary>pkg/utils/highlight_utils.go (1)</summary><blockquote>

<details>
<summary>pkg/schema/schema.go (2)</summary>

* `AtmosConfiguration` (13-45)
* `SyntaxHighlighting` (201-209)

</details>

</blockquote></details>

</details><details>
<summary>🪛 GitHub Check: codecov/patch</summary>

<details>
<summary>internal/exec/atlantis_generate_repo_config.go</summary>

[warning] 528-528: internal/exec/atlantis_generate_repo_config.go#L528
Added line #L528 was not covered by tests

</details>
<details>
<summary>cmd/docs.go</summary>

[warning] 105-105: cmd/docs.go#L105
Added line #L105 was not covered by tests

</details>
<details>
<summary>internal/exec/describe_dependents.go</summary>

[warning] 79-79: internal/exec/describe_dependents.go#L79
Added line #L79 was not covered by tests

</details>
<details>
<summary>internal/exec/describe_workflows.go</summary>

[warning] 79-79: internal/exec/describe_workflows.go#L79
Added line #L79 was not covered by tests

</details>
<details>
<summary>internal/exec/atmos.go</summary>

[warning] 111-111: internal/exec/atmos.go#L111
Added line #L111 was not covered by tests

---

[warning] 123-123: internal/exec/atmos.go#L123
Added line #L123 was not covered by tests

</details>
<details>
<summary>internal/exec/describe_stacks.go</summary>

[warning] 139-139: internal/exec/describe_stacks.go#L139
Added line #L139 was not covered by tests

</details>
<details>
<summary>internal/exec/describe_affected.go</summary>

[warning] 208-211: internal/exec/describe_affected.go#L208-L211
Added lines #L208 - L211 were not covered by tests

---

[warning] 213-216: internal/exec/describe_affected.go#L213-L216
Added lines #L213 - L216 were not covered by tests

---

[warning] 284-284: internal/exec/describe_affected.go#L284
Added line #L284 was not covered by tests

---

[warning] 327-327: internal/exec/describe_affected.go#L327
Added line #L327 was not covered by tests

</details>
<details>
<summary>cmd/describe_config.go</summary>

[warning] 19-25: cmd/describe_config.go#L19-L25
Added lines #L19 - L25 were not covered by tests

---

[warning] 27-30: cmd/describe_config.go#L27-L30
Added lines #L27 - L30 were not covered by tests

---

[warning] 32-35: cmd/describe_config.go#L32-L35
Added lines #L32 - L35 were not covered by tests

---

[warning] 37-42: cmd/describe_config.go#L37-L42
Added lines #L37 - L42 were not covered by tests

---

[warning] 45-45: cmd/describe_config.go#L45
Added line #L45 was not covered by tests

---

[warning] 49-49: cmd/describe_config.go#L49
Added line #L49 was not covered by tests

</details>
<details>
<summary>pkg/utils/json_utils.go</summary>

[warning] 27-28: pkg/utils/json_utils.go#L27-L28
Added lines #L27 - L28 were not covered by tests

---

[warning] 33-33: pkg/utils/json_utils.go#L33
Added line #L33 was not covered by tests

---

[warning] 37-37: pkg/utils/json_utils.go#L37
Added line #L37 was not covered by tests

---

[warning] 54-54: pkg/utils/json_utils.go#L54
Added line #L54 was not covered by tests

</details>
<details>
<summary>cmd/describe_component.go</summary>

[warning] 24-25: cmd/describe_component.go#L24-L25
Added lines #L24 - L25 were not covered by tests

---

[warning] 88-88: cmd/describe_component.go#L88
Added line #L88 was not covered by tests

</details>
<details>
<summary>internal/exec/describe_config.go</summary>

[warning] 79-80: internal/exec/describe_config.go#L79-L80
Added lines #L79 - L80 were not covered by tests

---

[warning] 84-85: internal/exec/describe_config.go#L84-L85
Added lines #L84 - L85 were not covered by tests

---

[warning] 92-93: internal/exec/describe_config.go#L92-L93
Added lines #L92 - L93 were not covered by tests

</details>
<details>
<summary>pkg/utils/highlight_utils.go</summary>

[warning] 33-33: pkg/utils/highlight_utils.go#L33
Added line #L33 was not covered by tests

---

[warning] 175-175: pkg/utils/highlight_utils.go#L175
Added line #L175 was not covered by tests

</details>
<details>
<summary>pkg/pager/model.go</summary>

[warning] 132-133: pkg/pager/model.go#L132-L133
Added lines #L132 - L133 were not covered by tests

---

[warning] 146-147: pkg/pager/model.go#L146-L147
Added lines #L146 - L147 were not covered by tests

---

[warning] 186-199: pkg/pager/model.go#L186-L199
Added lines #L186 - L199 were not covered by tests

</details>
<details>
<summary>internal/exec/describe_component.go</summary>

[warning] 100-101: internal/exec/describe_component.go#L100-L101
Added lines #L100 - L101 were not covered by tests

---

[warning] 115-116: internal/exec/describe_component.go#L115-L116
Added lines #L115 - L116 were not covered by tests

---

[warning] 123-124: internal/exec/describe_component.go#L123-L124
Added lines #L123 - L124 were not covered by tests

---

[warning] 128-129: internal/exec/describe_component.go#L128-L129
Added lines #L128 - L129 were not covered by tests

---

[warning] 136-137: internal/exec/describe_component.go#L136-L137
Added lines #L136 - L137 were not covered by tests

</details>

</details>
<details>
<summary>🪛 golangci-lint (1.64.8)</summary>

<details>
<summary>pkg/utils/json_utils.go</summary>

[error] 37-37: error is not nil (line 35) but it returns nil

(nilerr)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: Summary

</details>

<details>
<summary>🔇 Additional comments (70)</summary><blockquote>

<details>
<summary>tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden (1)</summary>

`70-70`: **Type change for pager setting looks good.**

The change from boolean to string representation for the pager setting aligns with the PR objective of implementing a more flexible pager configuration system. Using "0" as a string value to disable the pager is a logical choice.

</details>
<details>
<summary>tests/snapshots/TestCLICommands_atmos_describe_config_imports.stdout.golden (1)</summary>

`113-113`: **Type change for pager setting implemented correctly.**

The change from boolean to string representation for the pager setting aligns with the PR objective. Using "1" as a string value to enable the pager is consistent with the implementation approach seen in other files.

</details>
<details>
<summary>tests/snapshots/TestCLICommands_atmos_describe_configuration.stderr.golden (1)</summary>

`16-16`: **Debug log for pager failure is appropriate.**

This new debug log entry properly indicates that the pager failed to load, which is expected in a test environment. The error handling reflects the robust implementation of the pager functionality.

</details>
<details>
<summary>tests/snapshots/TestCLICommands_atmos_describe_config_imports.stderr.golden (1)</summary>

`20-20`: **Debug log for pager failure is properly implemented.**

This debug log entry correctly indicates that the pager failed, which is expected behavior in a test environment. The consistent error reporting across different commands shows attention to detail in the implementation.

</details>
<details>
<summary>pkg/config/default.go (1)</summary>

`58-58`: **Good choice updating the Pager field to "less"**

Changing from boolean to string type enhances flexibility by specifying which pager program to use rather than just enabling/disabling the feature. The "less" default is standard and widely available across systems.

</details>
<details>
<summary>cmd/describe.go (1)</summary>

`18-18`: **Flag added with appropriate default value**

Adding the `--pager` flag with default "true" maintains backward compatibility while giving users explicit control over the paging experience. This aligns well with the PR objectives.

</details>
<details>
<summary>Makefile (1)</summary>

`64-64`: **Improved test coverage tracking**

Adding the `-coverpkg=./...` flag ensures coverage analysis across all packages, not just those explicitly tested. This will provide more accurate metrics for the new pager functionality spread across multiple packages.

</details>
<details>
<summary>tests/test-cases/demo-stacks.yaml (3)</summary>

`77-78`: **Proper test setup for non-interactive testing**

Disabling the pager in this test case prevents interactive behavior that would break automated testing.

---

`96-97`: **Consistent test environment configuration**

Disabling the pager consistently across related tests ensures deterministic output without interactive pager prompts.

---

`118-119`: **Test environment properly configured**

The ATMOS_PAGER environment variable is correctly set to false, maintaining the pattern established in previous test cases and ensuring consistent non-interactive test execution.

</details>
<details>
<summary>website/docs/cli/commands/describe/describe-component.mdx (1)</summary>

`58-59`: **Good addition of a practical example for the pager flag.**

The example clearly shows how to use the `--pager` flag with a specific pager like `more`, which helps users understand the practical application of this feature.

</details>
<details>
<summary>pkg/atlantis/atlantis_generate_repo_config_test.go (2)</summary>

`18-18`: **Updated test to match new function signature.**

The test now correctly passes the CLI configuration pointer to the `PrintAsYAML` function, consistent with the implementation change.

---

`40-40`: **Updated test to match new function signature.**

The test now correctly passes the CLI configuration pointer to the `PrintAsYAML` function, ensuring that output formatting respects the user's configuration settings.

</details>
<details>
<summary>pkg/schema/schema.go (1)</summary>

`191-191`: **Changed pager type from boolean to string for more flexibility.**

This change improves configuration flexibility by allowing specific pager applications to be specified rather than just a binary enabled/disabled state.

</details>
<details>
<summary>go.mod (1)</summary>

`13-13`: **Dependencies added to support new terminal pager functionality.**

These four promoted dependencies provide the necessary functionality for implementing a robust terminal pager, including clipboard support, proper text width handling, ANSI sequence processing, and text reflowing capabilities.



Also applies to: 51-51, 55-56

</details>
<details>
<summary>internal/exec/atmos.go (2)</summary>

`123-123`: **Configuration now passed to PrintAsYAML for pager support.**

Same update pattern as the previous instance - passing atmosConfig to enable pager and syntax highlighting functionality.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 123-123: internal/exec/atmos.go#L123
Added line #L123 was not covered by tests

</details>

</details>

---

`111-111`: <details>
<summary>✅ Verification successful</summary>

**Configuration now passed to PrintAsYAML for pager support.**

The PrintAsYAML function now receives the atmosConfig pointer to enable pager and syntax highlighting functionality based on user settings.


---

🏁 Script executed:

```shell
#!/bin/bash
# Verify other instances of PrintAsYAML in the codebase have been updated
rg "PrintAsYAML\([^&]" --type go
```

Length of output: 962

---



</details>

**All `PrintAsYAML` calls now include the config**

Verified that every invocation—from `pkg/utils/yaml_utils.go` and its tests in `yq_test.go` through `internal/exec/file_utils.go`—uses the updated `atmosConfig` parameter. No further issues found.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 111-111: internal/exec/atmos.go#L111
Added line #L111 was not covered by tests

</details>

</details>

</details>
<details>
<summary>cmd/docs.go (1)</summary>

`105-105`: **Updated to use IsPagerEnabled() method instead of direct property access.**

This change transitions from accessing a boolean property to using a method that can implement more complex logic for determining pager enablement, allowing for string-based configuration and environment variable support.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 105-105: cmd/docs.go#L105
Added line #L105 was not covered by tests

</details>

</details>

</details>
<details>
<summary>tests/snapshots/TestCLICommands_atmos_describe_config_-f_yaml.stdout.golden (1)</summary>

`35-48`: **Updated test snapshot with new terminal configuration structure.**

The snapshot now includes the expanded terminal configuration section with pager settings and syntax highlighting options. The pager is set to "0" to disable it in tests, ensuring predictable output for assertions.

</details>
<details>
<summary>internal/exec/describe_stacks.go (1)</summary>

`139-139`: <details>
<summary>❓ Verification inconclusive</summary>

**Consistent update to function call signature.**

The change correctly adds the `&atmosConfig` pointer as the first parameter to the `printOrWriteToFile` function call, aligning with the broader refactoring to support pager features and syntax highlighting.


Run this script to check test coverage for this line:

---

🏁 Script executed:

```shell
#!/bin/bash
# Check test coverage for the new line of code
go test -v -cover ./internal/exec/... -coverprofile=cover.out
grep -A 5 -B 5 "describe_stacks.go:139" cover.out || echo "Line 139 not covered by tests"
```

Length of output: 46399

---



</details>

**Verify test coverage for the updated printOrWriteToFile call**

The change adding `&atmosConfig` as the first argument to `printOrWriteToFile` at line 139 in `internal/exec/describe_stacks.go` looks correct, but the coverage script didn’t conclusively report whether this line is exercised by tests. Please confirm that the new signature is covered.

• File: internal/exec/describe_stacks.go  
• Line: 139

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 139-139: internal/exec/describe_stacks.go#L139
Added line #L139 was not covered by tests

</details>

</details>

</details>
<details>
<summary>pkg/utils/yq_test.go (1)</summary>

`68-68`: **LGTM: Consistent function signature updates.**

All calls to `PrintAsYAML` correctly updated to include `atmosConfig` as the first parameter, maintaining consistency with the refactored function signature.



Also applies to: 76-76, 84-84, 92-92, 100-100, 108-108, 120-120, 132-132, 144-144, 155-155, 161-161, 167-167, 173-173

</details>
<details>
<summary>tests/snapshots/TestCLICommands_atmos_describe_configuration.stdout.golden (1)</summary>

`48-61`: **Snapshot updated with new terminal configuration settings.**

The snapshot now includes the required terminal configuration section with pager settings and syntax highlighting options, correctly reflecting the new CLI capabilities.

</details>
<details>
<summary>pkg/utils/json_utils_test.go (1)</summary>

`1-33`: **Good test for the refactored PrintAsJSON function.**

This test effectively verifies that the PrintAsJSON function works correctly with the new AtmosConfiguration parameter, testing the complete syntax highlighting configuration path.

</details>
<details>
<summary>internal/exec/describe_workflows.go (1)</summary>

`79-82`: <details>
<summary>✅ Verification successful</summary>

**Added config parameter to support pager functionality**

Function call updated to include the atmosConfig pointer as the first parameter, enabling the pager and syntax highlighting capabilities.


---

🏁 Script executed:

```shell
#!/bin/bash
# Description: Verify consistent printOrWriteToFile function signature usage

# Check all instances of printOrWriteToFile to ensure they include atmosConfig
rg "printOrWriteToFile\(\&?atmos" --type go
```

Length of output: 638

---



</details>

**Approve config parameter addition**  
Verified that `printOrWriteToFile` is invoked with `&atmosConfig` in all instances (describe_component.go, describe_workflows.go, describe_stacks.go, describe_dependents.go, describe_affected.go). No further changes required.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 79-79: internal/exec/describe_workflows.go#L79
Added line #L79 was not covered by tests

</details>

</details>

</details>
<details>
<summary>tests/cli_describe_component_test.go (1)</summary>

`10-18`: **Good test coverage for pager functionality**

This test successfully validates that the CLI command correctly processes the `--pager` flag with the "more" pager. The test ensures the command completes successfully when the pager option is specified.

</details>
<details>
<summary>pkg/schema/schema_test.go (1)</summary>

`40-71`: **Comprehensive test coverage for IsPagerEnabled method**

This test thoroughly validates the pager enablement logic with multiple test cases. It covers all expected input patterns including empty string, lowercase values that should enable the pager ("on", "less", "true", "yes", "y", "1"), and values that should disable it ("off", "false", "no", "n", "0").

The test also correctly verifies case sensitivity by checking that "ON" doesn't enable the pager.

</details>
<details>
<summary>internal/exec/file_utils.go (3)</summary>

`33-33`: **Added AtmosConfiguration parameter for highlighting support.**

This change adds the necessary configuration context for syntax highlighting in output rendering.

---

`41-41`: **Updated PrintAsYAML call to pass atmosConfig.**

The function call has been properly updated to match the signature changes in the utils package.

---

`54-54`: **Updated PrintAsJSON call to pass atmosConfig.**

The function call has been properly updated to match the signature changes in the utils package.

</details>
<details>
<summary>pkg/config/load.go (2)</summary>

`103-103`: **Environment variable bindings for pager configuration.**

Proper binding of both ATMOS_PAGER and standard PAGER environment variables following the project's patterns.

---

`121-121`: <details>
<summary>❌ Incorrect review comment</summary>

**Default pager setting needs clarification.**

The default setting is a boolean `true`, but based on context from the AI summary, this is later changed to a string value of "less". Make sure this intermediary boolean value doesn't cause any type conversion issues.

---

🏁 Script executed:

```shell
#!/bin/bash
# Look for the type definition of pager setting in schema files
rg -A 5 "terminal.*struct" pkg/schema/
# Look for pager type usage
rg "settings\.terminal\.pager" --type=go
```

Length of output: 1178

---

🏁 Script executed:

```shell
#!/bin/bash
# Dump the Terminal struct definition to inspect the Pager field type
rg -A20 -B5 'type Terminal' pkg/schema/schema.go
```

Length of output: 1890

---



</details>

**Pager default type is handled correctly**

Viper will cast the boolean `true` default to the string `"true"` when you call `GetString`, and `Terminal.Pager` is defined as a `string`. The `IsPagerEnabled` method explicitly checks for `"true"`, so there’s no type‐conversion gap and no hidden `"less"` value being applied.

• No code path overrides the default to `"less"`.  
• `v.SetDefault("settings.terminal.pager", true)` → `GetString` → `"true"` → handled by `IsPagerEnabled`.



> Likely an incorrect or invalid review comment.

</details>
<details>
<summary>internal/exec/describe_affected.go (2)</summary>

`284-284`: **Updated printOrWriteToFile call with atmosConfig parameter.**

The function call has been updated correctly to match the updated function signature in file_utils.go.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 284-284: internal/exec/describe_affected.go#L284
Added line #L284 was not covered by tests

</details>

</details>

---

`327-327`: **Updated printOrWriteToFile call with atmosConfig parameter.**

The function call has been updated correctly to match the updated function signature in file_utils.go.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 327-327: internal/exec/describe_affected.go#L327
Added line #L327 was not covered by tests

</details>

</details>

</details>
<details>
<summary>pkg/utils/yaml_utils.go (1)</summary>

`53-63`: **The new GetHighlightedYAML function handles errors properly**

Good implementation that properly handles errors from both YAML conversion and highlighting. I like that it returns the original YAML if highlighting fails rather than returning nothing.

</details>
<details>
<summary>pkg/pager/pager.go (3)</summary>

`8-11`: **Good interface design with mockgen for testability**

The PageCreator interface is well-designed and includes mockgen for generating test mocks. This promotes testability and clean separation of concerns.

---

`17-21`: **Factory pattern implemented correctly**

The factory function correctly creates and initializes the interface implementation with appropriate defaults.

---

`23-37`: <details>
<summary>❌ Incorrect review comment</summary>

**Potential window sizing issues**

The viewport is initialized with size (0, 0) but there's no code to resize it based on terminal dimensions. This could lead to display issues if the viewport size isn't properly set elsewhere.

---

🏁 Script executed:

```shell
#!/bin/bash
# Description: Find where viewport dimensions are set in the model

# Search for viewport resize operations in model.go
if [ -f "pkg/pager/model.go" ]; then
  echo "Checking model.go for viewport resize:"
  grep -n "viewport.*[Ww]idth\|viewport.*[Hh]eight\|viewport.*[Ss]ize" pkg/pager/model.go
else
  # If model.go doesn't exist, search more broadly
  echo "model.go not found, searching broadly for viewport resize:"
  rg -n "viewport.*[Ww]idth\|viewport.*[Hh]eight\|viewport.*[Ss]ize" pkg/pager/
fi
```

Length of output: 516

---



</details>

**Viewport sizing is already handled in model.go**  
The model listens for tea.WindowSizeMsg and updates the viewport’s width and height accordingly, so no additional resizing is needed in Run:

• pkg/pager/model.go:162 – initializes viewport with actual msg.Width and msg.Height-verticalMarginHeight  
• pkg/pager/model.go:167-168 – sets m.viewport.Width = msg.Width and m.viewport.Height = msg.Height – verticalMarginHeight  
• pkg/pager/model.go:254-255 – updates m.viewport.Width = w and m.viewport.Height = h – statusBarHeight  
• pkg/pager/model.go:261 – further adjusts height for pagerHelpHeight  

No changes required here. 

> Likely an incorrect or invalid review comment.

</details>
<details>
<summary>internal/exec/describe_component_test.go (2)</summary>

`13-34`: **Well-structured test setup with mocked dependencies**

The test properly mocks all required dependencies and provides reasonable default behaviors. This makes the tests more focused and resilient to changes in other parts of the codebase.

---

`36-97`: **Comprehensive test cases cover multiple scenarios**

The test cases cover a good range of scenarios including different formats, pager settings, and query parameters. This provides good coverage of the functionality.

</details>
<details>
<summary>cmd/describe_config.go (3)</summary>

`7-8`: **Good addition of essential imports.**

The added imports for configuration and schema packages are necessary for working with Atmos's CLI configuration system, which is required for the pager feature implementation.

---

`19-35`: **Proper error handling pattern adopted.**

The refactoring to use `RunE` instead of `Run` is a significant improvement as it allows for proper error propagation. The explicit flag retrieval with error checking follows Go best practices.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 19-25: cmd/describe_config.go#L19-L25
Added lines #L19 - L25 were not covered by tests

---

[warning] 27-30: cmd/describe_config.go#L27-L30
Added lines #L27 - L30 were not covered by tests

---

[warning] 32-35: cmd/describe_config.go#L32-L35
Added lines #L32 - L35 were not covered by tests

</details>

</details>

---

`37-43`: **Appropriately handling pager flag override.**

This code correctly updates the Terminal.Pager setting from command-line flags when explicitly provided, allowing users to override the config file setting.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 37-42: cmd/describe_config.go#L37-L42
Added lines #L37 - L42 were not covered by tests

</details>

</details>

</details>
<details>
<summary>pkg/pager/mock_pager.go (1)</summary>

`1-48`: **Clean mock implementation for testing.**

This auto-generated mock implementation is correctly structured for testing the PageCreator interface. The mock provides the necessary methods to verify interactions with the pager during unit tests, which is essential for testing the new pager functionality without launching a real pager UI.

</details>
<details>
<summary>pkg/pager/model_test.go (5)</summary>

`14-18`: **Well-structured test for Init method.**

Good test coverage for the Init method, properly verifying its return value.

---

`20-81`: **Comprehensive test coverage for Update method.**

The test suite thoroughly covers all key message types and scenarios for the Update method, including keyboard commands, window sizing, and viewport updates. The assertions verify both state changes and return values.

---

`83-106`: **Thorough testing of View method states.**

Tests appropriately cover both the ready and not-ready states for the View method, with clear assertions checking for expected content elements.

---

`108-132`: **Good coverage of footerView functionality.**

Tests handle both normal display and edge cases like zero line length scenarios for the footer view.

---

`151-163`: **Good styling function test coverage.**

These tests verify that the styling functions properly render content with additional styling elements.

</details>
<details>
<summary>cmd/describe_component.go (6)</summary>

`4-4`: **Appropriate import addition.**

The errors package is correctly added to support the new error handling.

---

`18-19`: **Improved argument validation using Cobra features.**

Changing to `cobra.ExactArgs(1)` is a better approach than the previous `MinimumNArgs(1)` as it enforces exactly one component argument, preventing unintended behavior with extra arguments.

---

`27-45`: **Thorough flag parsing with error checking.**

The code now properly retrieves all required flags with error checking, which makes the command more robust against configuration issues.

---

`46-58`: **Clean, structured parameter passing.**

Using a structured parameter object with the executor pattern improves code readability and maintainability. This approach makes it easier to add new parameters in the future without changing function signatures.

---

`70-70`: **Simpler flag description.**

Good simplification of the format flag description, removing unnecessary detail about the default value which is already handled by Cobra.

---

`84-90`: <details>
<summary>✅ Verification successful</summary>

**Potentially aggressive error handling approach.**

While the function's comment accurately describes its purpose, using `panic` for flag retrieval errors is a strong reaction. However, as noted, these are developer errors that should be caught during development.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check if this panic approach is used consistently across the codebase
rg "panic\(" cmd/ -A 1 -B 2
```

Length of output: 209

---



</details>

**No changes needed: panic is used appropriately for developer errors**  
I searched the `cmd/describe_component.go` file and found this is the only `panic(err)` call in that directory. Since this helper surfaces a developer-only flag retrieval mistake (not a user-facing error), panicking here is a reasonable guard.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 88-88: cmd/describe_component.go#L88
Added line #L88 was not covered by tests

</details>

</details>

</details>
<details>
<summary>pkg/utils/json_utils.go (2)</summary>

`15-22`: **Good refactoring to accept AtmosConfiguration pointer.**

The function now properly handles the configuration pointer needed for the pager feature implementation. This change aligns with PR objectives to implement paging for describe commands.

---

`24-40`: **Well-structured helper function with good fallback behavior.**

The new `GetHighlightedJSON` function centralizes JSON highlighting logic and gracefully falls back to plain JSON when highlighting fails. This supports the pager feature while maintaining reliability.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 golangci-lint (1.64.8)</summary>

[error] 37-37: error is not nil (line 35) but it returns nil

(nilerr)

</details>
<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 27-28: pkg/utils/json_utils.go#L27-L28
Added lines #L27 - L28 were not covered by tests

---

[warning] 33-33: pkg/utils/json_utils.go#L33
Added line #L33 was not covered by tests

---

[warning] 37-37: pkg/utils/json_utils.go#L37
Added line #L37 was not covered by tests

</details>

</details>

</details>
<details>
<summary>internal/exec/describe_config_test.go (7)</summary>

`12-15`: **Good test for custom error type.**

Testing the error message format is a solid practice.

---

`17-38`: **Good basic test setup and constructor validation.**

The test creates a proper configuration object with pager settings and verifies the constructor initializes all dependencies correctly.

---

`39-54`: **Well-structured test for pager integration with YAML format.**

Using mock expectations to verify the pager gets called with the correct title and content.

---

`56-70`: **Good test coverage for JSON format with pager.**

Similar to the YAML test, this verifies pager usage with JSON format.

---

`72-84`: **Important error case testing for invalid formats.**

Tests proper error handling for unsupported formats.

---

`86-116`: **Good testing for both non-TTY case and query evaluation.**

These tests verify the fallback behavior when TTY isn't available and check query evaluation.

---

`118-127`: **Excellent error case testing for query parsing failures.**

Testing error handling with malformed queries ensures robustness.

</details>
<details>
<summary>pkg/utils/highlight_utils.go (3)</summary>

`33-33`: **Good change to parameter type from value to pointer.**

This improves performance by avoiding unnecessary copying of the potentially large configuration struct.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 33-33: pkg/utils/highlight_utils.go#L33
Added line #L33 was not covered by tests

</details>

</details>

---

`75-75`: **Consistent pointer usage for configuration.**

This aligns with the changes in other functions, using pointers throughout the codebase.

---

`175-175`: **Updated function call to use pointer.**

This correctly adapts to the function signature change.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 175-175: pkg/utils/highlight_utils.go#L175
Added line #L175 was not covered by tests

</details>

</details>

</details>
<details>
<summary>internal/exec/describe_config.go (4)</summary>

`16-22`: **Good custom error type implementation.**

The `DescribeConfigFormatError` provides clear error messages for invalid format specifications.

---

`26-40`: **Well-structured dependency injection.**

The `describeConfigExec` struct and its constructor provide good encapsulation and testability through dependency injection.

---

`43-67`: **Clean implementation of command execution with pager support.**

The function properly evaluates queries, handles errors, and attempts to use the pager with fallback to direct printing when necessary.

---

`69-95`: **Good separation of pager-specific logic.**

The `viewConfig` method encapsulates format validation, content generation, and pager invocation, with appropriate error handling.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 79-80: internal/exec/describe_config.go#L79-L80
Added lines #L79 - L80 were not covered by tests

---

[warning] 84-85: internal/exec/describe_config.go#L84-L85
Added lines #L84 - L85 were not covered by tests

---

[warning] 92-93: internal/exec/describe_config.go#L92-L93
Added lines #L92 - L93 were not covered by tests

</details>

</details>

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T22:27:49Z
user: login: github-advanced-security[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T20:11:53Z
user: login: coderabbitai[bot]
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T20:16:52Z
user: login: coderabbitai[bot]
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T20:25:00Z
user: login: coderabbitai[bot]
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T20:40:26Z
user: login: coderabbitai[bot]
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T21:35:21Z
user: login: Benbentwo
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-05-14T23:39:16Z
user: login: coderabbitai[bot]
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T23:40:06Z
user: login: github-advanced-security[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T12:39:41Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 5**

<details>
<summary>🧹 Nitpick comments (3)</summary><blockquote>

<details>
<summary>cmd/describe_component.go (1)</summary><blockquote>

`82-88`: **Consider less extreme error handling than panic.**

While the comment explains the rationale, panic is a severe response that terminates the application. Consider using a more graceful error handling approach like logging the error and exiting with a non-zero status code.

```diff
-// We prefer to panic because this is a developer error.
-// checkFlagNotPresentError checks if the error is nil.
-func checkFlagNotPresentError(err error) {
-	if err != nil {
-		panic(err)
-	}
-}
+// checkFlagNotPresentError handles errors from flag retrieval.
+// These errors should never happen unless there's a developer error.
+func checkFlagNotPresentError(err error) {
+	if err != nil {
+		u.LogErrorAndExit(err)
+	}
+}
```

</blockquote></details>
<details>
<summary>cmd/describe_affected.go (1)</summary><blockquote>

`142-147`: **Cyclomatic complexity nudged over the threshold**

`parseDescribeAffectedCliArgs` hit a value of 11 (>10).  
After fixing the panic above, splitting flag parsing into its own helper would drop the count and keep the function easier to reason about.  
Not urgent, but worth tidying.

</blockquote></details>
<details>
<summary>internal/exec/describe_affected.go (1)</summary><blockquote>

`107-114`: **Heavy value parameter – pass by pointer**

`Execute(a DescribeAffectedCmdArgs)` copies a ~6 KB struct twice (caller + callee).  
Switch the signature to `Execute(a *DescribeAffectedCmdArgs)` (and update call-sites) to avoid the copy and quiet the linter.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: golangci-lint</summary>

[failure] 107-107: 
hugeParam: a is heavy (6120 bytes); consider passing it by pointer

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: .coderabbit.yaml**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 1ac04fcf096acbec89917306e75123e3643a5a48 and a0f8b4f10500ece443b09cde61fbaf9bde39eeff.

</details>

<details>
<summary>📒 Files selected for processing (6)</summary>

* `cmd/describe_affected.go` (3 hunks)
* `cmd/describe_component.go` (2 hunks)
* `internal/exec/describe_affected.go` (5 hunks)
* `internal/exec/describe_affected_test.go` (1 hunks)
* `internal/exec/describe_component_test.go` (1 hunks)
* `pkg/utils/highlight_utils.go` (3 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (2)</summary>

* internal/exec/describe_component_test.go
* pkg/utils/highlight_utils.go

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 GitHub Check: golangci-lint</summary>

<details>
<summary>cmd/describe_affected.go</summary>

[failure] 65-65: 
cyclomatic: function parseDescribeAffectedCliArgs has cyclomatic complexity 11 (> max enabled 10)

</details>
<details>
<summary>internal/exec/describe_affected.go</summary>

[failure] 107-107: 
hugeParam: a is heavy (6120 bytes); consider passing it by pointer

---

[failure] 168-168: 
hugeParam: a is heavy (6120 bytes); consider passing it by pointer

</details>
<details>
<summary>cmd/describe_component.go</summary>

[failure] 12-12: 
var `errInvalidFlag` is unused

</details>

</details>
<details>
<summary>🪛 golangci-lint (1.64.8)</summary>

<details>
<summary>internal/exec/describe_affected.go</summary>

[warning] 169-169: `if a.Query == ""` has complex nested blocks (complexity: 4)

(nestif)

</details>
<details>
<summary>cmd/describe_component.go</summary>

[error] 12-12: var `errInvalidFlag` is unused

(unused)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: Build (windows-latest, windows)
* GitHub Check: Summary

</details>

<details>
<summary>🔇 Additional comments (4)</summary><blockquote>

<details>
<summary>cmd/describe_component.go (4)</summary>

`41-42`: **Great addition of pager flag!**

This matches the PR objective to implement a native pager for describe commands. The implementation properly retrieves and passes the pager setting.

---

`46-56`: **Clean refactoring to structured parameters.**

The move to `DescribeComponentParams` struct makes the code more maintainable and easier to test. This is a solid improvement over passing individual arguments.

---

`68-68`: **Good simplification of format flag description.**

The simplified description is more concise while remaining clear.

---

`20-20`: **Good use of ExactArgs for validation.**

Using `cobra.ExactArgs(1)` is a solid improvement that ensures the command receives exactly one component argument.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T12:43:27Z
user: login: Benbentwo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T12:44:09Z
user: login: samtholiya
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T21:47:46Z
user: login: samtholiya
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T21:52:49Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T21:54:32Z
user: login: coderabbitai[bot]
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T21:57:19Z
user: login: Benbentwo
body: can you explain why the pager flag isn't a bool? I'm not following why we use certain strings. 
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-15T22:44:55Z

Review comments:
diff_hunk: @@ -76,7 +76,7 @@
 		res = dependents
 	}
 
-	err = printOrWriteToFile(format, file, res)
+	err = printOrWriteToFile(&atmosConfig, format, file, res)
path: internal/exec/describe_dependents.go
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Updated function call to support pager configuration.**

The code now correctly passes the CLI configuration to the output function, allowing for consistent pager and syntax highlighting behavior.


This line is currently not covered by tests according to static analysis:

---

🏁 Script executed:

```shell
#!/bin/bash
# Add a test to cover the describe_dependents execution with pager configuration
# Check for test files related to describe_dependents.go

echo "Checking for existing tests:"
find . -name "*describe_dependents*test.go"
```

Length of output: 155

---

🏁 Script executed:

```shell
#!/bin/bash
# Display the describe_dependents test file to check for coverage of pager configuration
echo "=== pkg/describe/describe_dependents_test.go ==="
sed -n '1,200p' pkg/describe/describe_dependents_test.go
```

Length of output: 1409

---



</details>

**Missing test coverage for pager configuration**

The existing tests in pkg/describe/describe_dependents_test.go only exercise the non-pager path (`false`). We need to add a test that enables the pager flag (`true`) to ensure the new printOrWriteToFile call correctly respects the CLI’s pager settings.

Files to update:
- pkg/describe/describe_dependents_test.go

Suggested addition (after TestDescribeDependents2):

```go
func TestDescribeDependentsWithPager(t *testing.T) {
    configAndStacksInfo := schema.ConfigAndStacksInfo{}
    atmosConfig, err := cfg.InitCliConfig(configAndStacksInfo, true)
    assert.Nil(t, err)

    component := "test/test-component"
    stack := "tenant1-ue2-test-1"

    // Enable pager output
    dependents, err := e.ExecuteDescribeDependents(atmosConfig, component, stack, true)
    assert.Nil(t, err)
    assert.Equal(t, 1, len(dependents))

    // Optionally verify behaviour of pager, e.g. no errors when printing
    outputYAML, err := u.ConvertToYAML(dependents)
    assert.Nil(t, err)
    t.Log("Pager output:\n", outputYAML)
}
```

This ensures the new pager-enabled branch is covered.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 79-79: internal/exec/describe_dependents.go#L79
Added line #L79 was not covered by tests

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In internal/exec/describe_dependents.go at line 79, the call to
printOrWriteToFile now supports pager configuration but lacks test coverage for
the pager-enabled path. To fix this, add a new test function in
pkg/describe/describe_dependents_test.go (e.g., TestDescribeDependentsWithPager)
that initializes the CLI config with pager enabled, calls
ExecuteDescribeDependents with the pager flag set to true, and asserts expected
results and no errors. This will ensure the pager functionality is properly
tested.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-13T22:27:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -525,7 +525,7 @@
 			return err
 		}
 	} else {
-		err = u.PrintAsYAML(atlantisYaml)
+		err = u.PrintAsYAML(&atmosConfig, atlantisYaml)
 		if err != nil {
path: internal/exec/atlantis_generate_repo_config.go
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Updated function call to match new signature**

The code now passes the `&atmosConfig` parameter to `PrintAsYAML`, aligning with the updated function signature that supports pager functionality and syntax highlighting.


---

🏁 Script executed:

```shell
#!/bin/bash
# Description: Check if PrintAsYAML is consistently called with atmosConfig parameter throughout the codebase

# Search for all PrintAsYAML calls and verify they include the atmosConfig parameter
rg "PrintAsYAML\(\&?atmos" --type go
```

Length of output: 1392

---

🏁 Script executed:

```shell
#!/bin/bash
set -eu
echo "=== internal/exec/file_utils.go context ==="
rg -n "PrintAsYAML" -C3 internal/exec/file_utils.go || true
echo
echo "=== pkg/utils/yq_test.go (first 40 lines) ==="
sed -n '1,40p' pkg/utils/yq_test.go || true
```

Length of output: 1288

---



</details>

**Align all `PrintAsYAML` calls with the new pointer-based signature**

We’ve spotted inconsistent calls that still pass `atmosConfig` by value instead of as a pointer. Please update these locations:

• internal/exec/file_utils.go (around line 41)  
  ```diff
  -	err := u.PrintAsYAML(atmosConfig, data)
  +	err := u.PrintAsYAML(&atmosConfig, data)
  ```  

• pkg/utils/yq_test.go (multiple occurrences)  
  ```diff
  -	err = PrintAsYAML(atmosConfig, res)
  +	err = PrintAsYAML(&atmosConfig, res)
  ```  

After these changes, all calls to `PrintAsYAML` will consistently pass `*schema.AtmosConfiguration`. 

> Committable suggestion skipped: line range outside the PR's diff.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 528-528: internal/exec/atlantis_generate_repo_config.go#L528
Added line #L528 was not covered by tests

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In internal/exec/atlantis_generate_repo_config.go at lines 528-529, the call to
PrintAsYAML correctly passes atmosConfig as a pointer. However, ensure that all
other calls to PrintAsYAML in the codebase, specifically in
internal/exec/file_utils.go around line 41 and multiple places in
pkg/utils/yq_test.go, are updated to pass atmosConfig as a pointer as well.
Review those files and change any PrintAsYAML(atmosConfig) calls to
PrintAsYAML(&atmosConfig) to maintain consistency with the new function
signature.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-13T22:27:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -205,6 +205,16 @@
 
 // ExecuteDescribeAffectedCmd executes `describe affected` command
 func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error {
+	info, err := ProcessCommandLineArgs("", cmd, args, nil)
+	if err != nil {
+		return err
+	}
+
+	atmosConfig, err := cfg.InitCliConfig(info, true)
+	if err != nil {
+		return err
+	}
path: internal/exec/describe_affected.go
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>❓ Verification inconclusive</summary>

**Initialized CLI config early to support paging functionality.**

Moving the CLI config initialization to the beginning of the function ensures the configuration is available for the pager feature.


The static analysis indicates these lines aren't covered by tests. Consider adding tests to improve coverage:

---

🏁 Script executed:

```shell
#!/bin/bash
# Check existing test files that might be extended
find internal/exec -name "*_test.go" | grep -i describe_affected
```

Length of output: 66

---



</details>

**Add tests for CLI config initialization in describe_affected.go**

It looks like there are no existing tests covering the new early-InitCliConfig code in internal/exec/describe_affected.go. To improve coverage and guard the paging feature, please:

• Create a test file, e.g. `internal/exec/describe_affected_test.go`  
• Add cases for  
  – successful `ProcessCommandLineArgs` → `InitCliConfig(info, true)`  
  – error from `ProcessCommandLineArgs`  
  – error from `InitCliConfig`  

This will ensure the paging support and error paths remain exercised.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 208-211: internal/exec/describe_affected.go#L208-L211
Added lines #L208 - L211 were not covered by tests

---

[warning] 213-216: internal/exec/describe_affected.go#L213-L216
Added lines #L213 - L216 were not covered by tests

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In internal/exec/describe_affected.go around lines 208 to 216, the new early
initialization of the CLI config via InitCliConfig is not covered by tests. To
fix this, create or extend the test file internal/exec/describe_affected_test.go
with test cases that cover: successful execution of ProcessCommandLineArgs
followed by InitCliConfig(info, true), handling of errors returned from
ProcessCommandLineArgs, and handling of errors returned from InitCliConfig. This
will ensure the paging feature and error handling paths are properly tested.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-13T22:27:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -41,21 +41,25 @@
 )
 
 // PrintAsYAML prints the provided value as YAML document to the console
-func PrintAsYAML(data any) error {
-	y, err := ConvertToYAML(data)
+func PrintAsYAML(atmosConfig *schema.AtmosConfiguration, data any) error {
+	y, err := GetHighlightedYAML(atmosConfig, data)
 	if err != nil {
 		return err
 	}
+	PrintMessage(y)
+	return nil
+}
path: pkg/utils/yaml_utils.go
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Function signature change - add check for nil config**

The function now takes `atmosConfig *schema.AtmosConfiguration` parameter, but there's no check for a nil pointer. This could cause a panic if `HighlightCodeWithConfig` dereferences a nil config.


```diff
func PrintAsYAML(atmosConfig *schema.AtmosConfiguration, data any) error {
	y, err := GetHighlightedYAML(atmosConfig, data)
	if err != nil {
		return err
	}
	PrintMessage(y)
	return nil
}
```


> Committable suggestion skipped: line range outside the PR's diff.

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In pkg/utils/yaml_utils.go around lines 44 to 51, the function PrintAsYAML
accepts a pointer atmosConfig but does not check if it is nil before use. To fix
this, add a nil check for atmosConfig at the start of the function and return an
appropriate error if it is nil to prevent potential panics when dereferencing it
in HighlightCodeWithConfig.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-13T22:27:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,48 @@
+package tests
+
+import (
+	"os"
+	"testing"
+
+	"github.com/cloudposse/atmos/cmd"
+)
+
+func ExecuteCommand(args []string) error {
+	// Set the command line arguments
+	os.Args = args
+
+	// Execute the command
+	return cmd.Execute()
+}
+
+func TestDescribeComponentJSON(t *testing.T) {
+	// Set up the environment variables
+	currentWd, _ := os.Getwd()
+	defer os.Chdir(currentWd)
+	os.Chdir("./fixtures/scenarios/atmos-providers-section")
+
+	t.Setenv("ATMOS_PAGER", "more")
+
+	// Execute the command
+	os.Args = []string{"atmos", "describe", "component", "component-1", "--stack", "nonprod", "--format", "json"}
+	err := cmd.Execute()
+	if err != nil {
+		t.Fatalf("Failed to execute command: %v", err)
+	}
+}
path: tests/describe_test.go
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Test would benefit from output validation**

The test sets up and runs the command but doesn't validate any output or behavior. Consider capturing stdout and asserting on the expected content to verify the command produces the correct output.


```diff
func TestDescribeComponentJSON(t *testing.T) {
	// Set up the environment variables
	currentWd, _ := os.Getwd()
	defer os.Chdir(currentWd)
	os.Chdir("./fixtures/scenarios/atmos-providers-section")

	t.Setenv("ATMOS_PAGER", "more")

+	// Capture stdout
+	originalStdout := os.Stdout
+	r, w, _ := os.Pipe()
+	os.Stdout = w
+	
+	// Ensure stdout is restored after test
+	defer func() {
+		os.Stdout = originalStdout
+	}()

	// Execute the command
	os.Args = []string{"atmos", "describe", "component", "component-1", "--stack", "nonprod", "--format", "json"}
	err := cmd.Execute()
	if err != nil {
		t.Fatalf("Failed to execute command: %v", err)
	}
	
+	// Close writer and read the output
+	w.Close()
+	out, _ := io.ReadAll(r)
+	output := string(out)
+	
+	// Assert on the output
+	assert.Contains(t, output, "component-1")
}
```


> Committable suggestion skipped: line range outside the PR's diff.

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In tests/describe_test.go around lines 18 to 32, the test runs the command but
does not validate its output. Modify the test to capture the standard output
during command execution and add assertions to verify that the output matches
the expected JSON content. This will ensure the test verifies the command's
behavior and output correctness.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-13T22:27:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,11 +16,37 @@
 	Long:               "This command displays the final, deep-merged CLI configuration after combining all relevant configuration files.",
 	FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
 	Args:               cobra.NoArgs,
-	Run: func(cmd *cobra.Command, args []string) {
-		err := e.ExecuteDescribeConfigCmd(cmd, args)
+	RunE: func(cmd *cobra.Command, args []string) error {
+		flags := cmd.Flags()
+
+		format, err := flags.GetString("format")
+		if err != nil {
+			return err
+		}
+
+		query, err := flags.GetString("query")
+		if err != nil {
+			return err
+		}
+
+		atmosConfig, err := cfg.InitCliConfig(schema.ConfigAndStacksInfo{}, false)
+		if err != nil {
+			return err
+		}
+
+		if cmd.Flags().Changed("pager") {
+			// TODO: update this post pr:https://github.com/cloudposse/atmos/pull/1174 is merged
+			atmosConfig.Settings.Terminal.Pager, err = cmd.Flags().GetString("pager")
+			if err != nil {
+				return err
+			}
+		}
+
+		err = e.NewDescribeConfig(&atmosConfig).ExecuteDescribeConfigCmd(query, format, "")
 		if err != nil {
 			u.PrintErrorMarkdown("", err, "")
 		}
+		return nil
path: cmd/describe_config.go
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Clean implementation using executor pattern.**

The use of the executor pattern with `NewDescribeConfig` makes the code more testable and maintainable by separating command parsing from execution logic. The error handling is proper, though errors are only printed and not propagated.


---

🏁 Script executed:

```shell
#!/bin/bash
# Check how the error is handled in similar commands
rg -A 5 "RunE: func\(cmd \*cobra\.Command, args \[\]string\) error" cmd/ | grep "return nil" -B 5
```

Length of output: 571

---

🏁 Script executed:

```shell
#!/bin/bash
# Verify where PrintErrorMarkdown is used
echo "=== PrintErrorMarkdown occurrences ==="
rg "PrintErrorMarkdown" -n

# Inspect the executor invocation and error handling in describe_config.go
echo "=== ExecuteDescribeConfigCmd context ==="
rg -C3 "ExecuteDescribeConfigCmd" cmd/describe_config.go

# Show the full RunE block to see how errors are returned or printed
echo "=== RunE block in describe_config.go ==="
rg -C5 "RunE: func(cmd \\*cobra\\.Command, args \\[\\]string\\) error" cmd/describe_config.go
```

Length of output: 6019

---

🏁 Script executed:

```shell
#!/bin/bash
# Correctly extract the full RunE block in describe_config.go
echo "=== RunE block in cmd/describe_config.go ==="
rg -n -C5 'RunE:' cmd/describe_config.go
```

Length of output: 667

---

🏁 Script executed:

```shell
#!/bin/bash
# Check for 'return nil' occurrences in the RunE block of describe_config.go
echo "=== return nil in cmd/describe_config.go ==="
rg -n "return nil" -C5 cmd/describe_config.go
```

Length of output: 405

---



</details>

**Ensure errors aren’t silently swallowed in describe_config.go**

The `ExecuteDescribeConfigCmd` error is currently printed but then swallowed by returning `nil`, leading to a zero‐exit code on failure. To match other `describe_*` commands and surface failures correctly, replace the `PrintErrorMarkdown` call with `PrintErrorMarkdownAndExit`:

• File: cmd/describe_config.go  
  Lines: ~45–49  

Suggested diff:
```diff
-       err = e.NewDescribeConfig(&atmosConfig).ExecuteDescribeConfigCmd(query, format, "")
-       if err != nil {
-           u.PrintErrorMarkdown("", err, "")
-       }
+       err = e.NewDescribeConfig(&atmosConfig).ExecuteDescribeConfigCmd(query, format, "")
+       if err != nil {
+           u.PrintErrorMarkdownAndExit("", err, "")
+       }
        return nil
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
        err = e.NewDescribeConfig(&atmosConfig).ExecuteDescribeConfigCmd(query, format, "")
        if err != nil {
            u.PrintErrorMarkdownAndExit("", err, "")
        }
        return nil
```

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 45-45: cmd/describe_config.go#L45
Added line #L45 was not covered by tests

---

[warning] 49-49: cmd/describe_config.go#L49
Added line #L49 was not covered by tests

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In cmd/describe_config.go around lines 45 to 49, the error from
ExecuteDescribeConfigCmd is printed using PrintErrorMarkdown but then the
function returns nil, causing the error to be swallowed and the process to exit
with zero status. To fix this, replace the PrintErrorMarkdown call with
PrintErrorMarkdownAndExit so that the error is printed and the process exits
with a non-zero status, ensuring failures are properly surfaced.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-13T22:27:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -12,27 +12,51 @@
 )
 
 // PrintAsJSON prints the provided value as JSON document to the console
-func PrintAsJSON(data any) error {
-	j, err := ConvertToJSON(data)
+func PrintAsJSON(atmosConfig *schema.AtmosConfiguration, data any) error {
+	highlighted, err := GetHighlightedJSON(atmosConfig, data)
 	if err != nil {
 		return err
 	}
+	PrintMessage(highlighted)
+	return nil
+}
+
+func GetHighlightedJSON(atmosConfig *schema.AtmosConfiguration, data any) (string, error) {
+	j, err := ConvertToJSON(data)
+	if err != nil {
+		return "", err
+	}
 
 	var prettyJSON bytes.Buffer
 	err = json.Indent(&prettyJSON, []byte(j), "", "  ")
 	if err != nil {
-		return err
+		return "", err
+	}
+	highlighted, err := HighlightCodeWithConfig(atmosConfig, prettyJSON.String())
+	if err != nil {
+		return prettyJSON.String(), nil
 	}
path: pkg/utils/json_utils.go
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Verify error handling logic.**

The function ignores the highlighting error and returns the un-highlighted but formatted JSON. This is good for graceful degradation, but consider adding a debug log to track these failures.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check how often highlighting might fail in existing code
rg -A 2 "HighlightCodeWithConfig\(" --type go
```

Length of output: 1081

---



</details>

**Add debug logging for JSON highlighting failures**

Currently, pkg/utils/json_utils.go swallows errors from `HighlightCodeWithConfig` and returns un-highlighted JSON without any trace, whereas pkg/utils/yaml_utils.go propagates them. To aid debugging, please:

- In pkg/utils/json_utils.go (around lines 35–38), insert a debug log before returning on error. For example:
  ```go
  highlighted, err := HighlightCodeWithConfig(atmosConfig, prettyJSON.String())
  if err != nil {
      log.Debugf("JSON highlighting failed: %v", err)
      return prettyJSON.String(), nil
  }
  ```
- Optionally, review whether you want to align this graceful-degradation pattern with yaml_utils.go’s propagation behavior.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 golangci-lint (1.64.8)</summary>

[error] 37-37: error is not nil (line 35) but it returns nil

(nilerr)

</details>
<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 37-37: pkg/utils/json_utils.go#L37
Added line #L37 was not covered by tests

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In pkg/utils/json_utils.go around lines 35 to 38, the error from
HighlightCodeWithConfig is currently ignored without any logging, which hinders
debugging. Add a debug log statement before returning the un-highlighted JSON on
error, using log.Debugf to record the error details. This will help trace
highlighting failures while maintaining graceful degradation. Optionally,
consider if you want to change this behavior to propagate errors like in
yaml_utils.go.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-13T22:27:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,389 @@
+package pager
+
+import (
+	"fmt"
+	"math"
+	"regexp"
+	"strings"
+	"time"
+
+	"github.com/atotto/clipboard"
+	"github.com/charmbracelet/bubbles/viewport"
+	tea "github.com/charmbracelet/bubbletea"
+	"github.com/charmbracelet/lipgloss"
+	"github.com/mattn/go-runewidth"
+	"github.com/muesli/ansi"
+	"github.com/muesli/reflow/truncate"
+	"github.com/muesli/termenv"
+)
+
+const (
+	minPercent               float64 = 0.0
+	maxPercent               float64 = 1.0
+	percentToStringMagnitude float64 = 100.0
+
+	statusMessageTimeout = time.Second * 3 // how long to show status messages like "stashed!"
+	ellipsis             = "…"
+	statusBarHeight      = 1
+)
+
+type pagerState int
+
+const (
+	pagerStateBrowse pagerState = iota
+	pagerStateStatusMessage
+)
+
+type pagerStatusMessage struct {
+	message string
+	isError bool
+}
+
+var (
+	pagerHelpHeight int
+
+	logo = statusBarHelpStyle(" \U0001F47D  ")
+
+	mintGreen = lipgloss.AdaptiveColor{Light: "#89F0CB", Dark: "#89F0CB"}
+	darkGreen = lipgloss.AdaptiveColor{Light: "#1C8760", Dark: "#1C8760"}
+	errorRed  = lipgloss.AdaptiveColor{Light: "#FF5555", Dark: "#FF5555"}
+	darkGray  = lipgloss.AdaptiveColor{Light: "#333333", Dark: "#333333"}
+
+	statusBarNoteFg = lipgloss.AdaptiveColor{Light: "#656565", Dark: "#7D7D7D"}
+	statusBarBg     = lipgloss.AdaptiveColor{Light: "#E6E6E6", Dark: "#242424"}
+
+	statusBarNoteStyle = lipgloss.NewStyle().
+				Foreground(statusBarNoteFg).
+				Background(statusBarBg).
+				Render
+
+	statusBarHelpStyle = lipgloss.NewStyle().
+				Foreground(statusBarNoteFg).
+				Background(lipgloss.AdaptiveColor{Light: "#DCDCDC", Dark: "#323232"}).
+				Render
+
+	statusBarMessageStyle = lipgloss.NewStyle().
+				Foreground(mintGreen).
+				Background(darkGreen).
+				Render
+	errorMessageStyle = lipgloss.NewStyle().
+				Foreground(errorRed).
+				Background(darkGray).
+				Render
+
+	statusBarMessageScrollPosStyle = lipgloss.NewStyle().
+					Foreground(mintGreen).
+					Background(darkGreen).
+					Render
+
+	statusBarMessageHelpStyle = lipgloss.NewStyle().
+					Foreground(lipgloss.Color("#B6FFE4")).
+					Background(green).
+					Render
+
+	helpViewStyle = lipgloss.NewStyle().
+			Foreground(statusBarNoteFg).
+			Background(lipgloss.AdaptiveColor{Light: "#f2f2f2", Dark: "#1B1B1B"}).
+			Render
+
+	green = lipgloss.Color("#04B575")
+)
+
+// Common stuff we'll need to access in all models.
+type commonModel struct {
+	width  int
+	height int
+}
+
+var (
+	titleStyle = func() lipgloss.Style {
+		b := lipgloss.RoundedBorder()
+		b.Right = "├"
+		return lipgloss.NewStyle().BorderStyle(b).Padding(0, 1)
+	}()
+
+	infoStyle = func() lipgloss.Style {
+		b := lipgloss.RoundedBorder()
+		b.Left = "┤"
+		return titleStyle.BorderStyle(b)
+	}()
+)
+
+type model struct {
+	title    string
+	content  string
+	ready    bool
+	viewport viewport.Model
+	common   commonModel
+	showHelp bool
+
+	state              pagerState
+	statusMessage      pagerStatusMessage
+	statusMessageTimer *time.Timer
+}
+
+func (m *model) Init() tea.Cmd {
+	return nil
+}
+
+var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;?]*[ -/]*[@-~]`)
+
+// StripANSI removes ANSI escape sequences (like terminal colors) from input.
+func StripANSI(input string) string {
+	return ansiRegex.ReplaceAllString(input, "")
+}
+
+func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+	var (
+		cmd  tea.Cmd
+		cmds []tea.Cmd
+	)
+
+	switch msg := msg.(type) {
+	case tea.KeyMsg:
+		return m.handleKeyPress(msg)
+
+	case statusMessageTimeoutMsg:
+		m.state = pagerStateBrowse
+		// Window size is received when starting up and on every resize
+	case tea.WindowSizeMsg:
+		m.common.width = msg.Width
+		m.common.height = msg.Height
+
+		footerHeight := lipgloss.Height(m.footerView())
+		verticalMarginHeight := footerHeight
+
+		if !m.ready {
+			// Since this program is using the full size of the viewport we
+			// need to wait until we've received the window dimensions before
+			// we can initialize the viewport. The initial dimensions come in
+			// quickly, though asynchronously, which is why we wait for them
+			// here.
+			m.viewport = viewport.New(msg.Width, msg.Height-verticalMarginHeight)
+			m.viewport.YPosition = 0
+			m.viewport.SetContent(m.content)
+			m.ready = true
+		} else {
+			m.viewport.Width = msg.Width
+			m.viewport.Height = msg.Height - verticalMarginHeight
+		}
+	}
+
+	// Handle keyboard and mouse events in the viewport
+	m.viewport, cmd = m.viewport.Update(msg)
+	cmds = append(cmds, cmd)
+
+	return m, tea.Batch(cmds...)
+}
+
+// handleKeyPress processes keyboard input and returns the updated model and command.
+func (m *model) handleKeyPress(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
+	var cmds []tea.Cmd
+
+	switch msg.String() {
+	case "q", "esc", "ctrl+c":
+		return m, tea.Quit
+	case "home", "g":
+		m.viewport.GotoTop()
+	case "end", "G":
+		m.viewport.GotoBottom()
+	case "c":
+		// Copy using OSC 52
+		termenv.Copy(StripANSI(m.content))
+		if err := clipboard.WriteAll(StripANSI(m.content)); err != nil {
+			cmds = append(cmds, m.showStatusMessage(pagerStatusMessage{"Failed to copy to clipboard", true}))
+		} else {
+			cmds = append(cmds, m.showStatusMessage(pagerStatusMessage{"Copied contents", false}))
+		}
+	case "?":
+		m.toggleHelp()
+	}
+
+	// Handle keyboard and mouse events in the viewport
+	var cmd tea.Cmd
+	m.viewport, cmd = m.viewport.Update(msg)
+	cmds = append(cmds, cmd)
+
+	return m, tea.Batch(cmds...)
+}
+
+type statusMessageTimeoutMsg applicationContext
+
+// applicationContext indicates the area of the application something applies
+// to. Occasionally used as an argument to commands and messages.
+type applicationContext int
+
+const (
+	stashContext applicationContext = iota
+	pagerContext
+)
+
+// Perform stuff that needs to happen after a successful markdown stash. Note
+// that the the returned command should be sent back the through the pager
+// update function.
+func (m *model) showStatusMessage(msg pagerStatusMessage) tea.Cmd {
+	// Show a success message to the user
+	m.state = pagerStateStatusMessage
+	m.statusMessage = msg
+
+	if m.statusMessageTimer != nil {
+		m.statusMessageTimer.Stop()
+	}
+
+	m.statusMessageTimer = time.NewTimer(statusMessageTimeout)
+
+	return waitForStatusMessageTimeout(pagerContext, m.statusMessageTimer)
+}
+
+func waitForStatusMessageTimeout(appCtx applicationContext, t *time.Timer) tea.Cmd {
+	return func() tea.Msg {
+		<-t.C
+		return statusMessageTimeoutMsg(appCtx)
+	}
+}
+
+func (m *model) toggleHelp() {
+	m.showHelp = !m.showHelp
+	m.setSize(m.common.width, m.common.height)
+	if m.viewport.PastBottom() {
+		m.viewport.GotoBottom()
+	}
+}
+
+func (m *model) setSize(w, h int) {
+	m.viewport.Width = w
+	m.viewport.Height = h - statusBarHeight
+
+	if m.showHelp {
+		if pagerHelpHeight == 0 {
+			pagerHelpHeight = strings.Count(m.helpView(), "\n")
+		}
+		m.viewport.Height -= (statusBarHeight + pagerHelpHeight)
+	}
path: pkg/pager/model.go
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Viewport height is reduced twice when help is shown**

When `showHelp` is true we subtract `statusBarHeight` a second time, so the
content area is one row smaller than necessary.



```diff
-		m.viewport.Height -= (statusBarHeight + pagerHelpHeight)
+		m.viewport.Height -= pagerHelpHeight
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
func (m *model) setSize(w, h int) {
    m.viewport.Width = w
    m.viewport.Height = h - statusBarHeight

    if m.showHelp {
        if pagerHelpHeight == 0 {
            pagerHelpHeight = strings.Count(m.helpView(), "\n")
        }
        m.viewport.Height -= pagerHelpHeight
    }
}
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In pkg/pager/model.go around lines 253 to 262, the viewport height is reduced by
statusBarHeight initially and then again inside the showHelp condition, causing
the height to be decreased twice when help is shown. To fix this, remove the
initial subtraction of statusBarHeight before the if statement and only subtract
it once inside the conditional block, adjusting the height correctly based on
whether help is shown or not.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-13T22:27:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -13,22 +15,59 @@
 	Short:              "Show configuration details for an Atmos component in a stack",
 	Long:               `Display the configuration details for a specific Atmos component within a designated Atmos stack, including its dependencies, settings, and overrides.`,
 	FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
-	Run: func(cmd *cobra.Command, args []string) {
+	Args:               cobra.ExactArgs(1),
+	RunE: func(cmd *cobra.Command, args []string) error {
 		// Check Atmos configuration
 		checkAtmosConfig()
 
-		err := e.ExecuteDescribeComponentCmd(cmd, args)
+		if len(args) != 1 {
+			return errors.New("invalid arguments. The command requires one argument `component`")
path: cmd/describe_component.go
user: login: github-advanced-security[bot]
body: do not define dynamic errors, use wrapped static errors instead: "errors.New(\"invalid arguments. The command requires one argument `component`\")"

[Show more details](https://github.com/cloudposse/atmos/security/code-scanning/883)
created_at: 2025-05-14T20:11:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -41,3 +80,11 @@
 
 	describeCmd.AddCommand(describeComponentCmd)
 }
+
+// checkFlagNotPresentError checks if the error is nil.
path: cmd/describe_component.go
user: login: github-advanced-security[bot]
body: Sentence should start with a capital letter

[Show more details](https://github.com/cloudposse/atmos/security/code-scanning/884)
created_at: 2025-05-14T20:11:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,66 +1,71 @@
 package exec
 
 import (
-	"github.com/pkg/errors"
+	log "github.com/charmbracelet/log"
 	"github.com/samber/lo"
-	"github.com/spf13/cobra"
 
+	"github.com/cloudposse/atmos/internal/tui/templates/term"
 	cfg "github.com/cloudposse/atmos/pkg/config"
+	"github.com/cloudposse/atmos/pkg/pager"
 	"github.com/cloudposse/atmos/pkg/schema"
 	u "github.com/cloudposse/atmos/pkg/utils"
 )
 
-// ExecuteDescribeComponentCmd executes `describe component` command.
-func ExecuteDescribeComponentCmd(cmd *cobra.Command, args []string) error {
-	if len(args) != 1 {
-		return errors.New("invalid arguments. The command requires one argument `component`")
-	}
-
-	_, err := cfg.InitCliConfig(schema.ConfigAndStacksInfo{}, true)
-	if err != nil {
-		return err
-	}
-
-	flags := cmd.Flags()
-
-	stack, err := flags.GetString("stack")
-	if err != nil {
-		return err
-	}
-
-	format, err := flags.GetString("format")
-	if err != nil {
-		return err
-	}
-
-	file, err := flags.GetString("file")
-	if err != nil {
-		return err
-	}
-
-	processTemplates, err := flags.GetBool("process-templates")
-	if err != nil {
-		return err
-	}
+type DescribeComponentParams struct {
+	Component            string
+	Stack                string
+	ProcessTemplates     bool
+	ProcessYamlFunctions bool
+	Skip                 []string
+	Query                string
+	Pager                string
+	Format               string
+	File                 string
+}
 
-	processYamlFunctions, err := flags.GetBool("process-functions")
-	if err != nil {
-		return err
-	}
+type DescribeComponentExec struct {
+	pageCreator              pager.PageCreator
+	printOrWriteToFile       func(atmosConfig *schema.AtmosConfiguration, format string, file string, data any) error
+	IsTTYSupportForStdout    func() bool
+	initCliConfig            func(configAndStacksInfo schema.ConfigAndStacksInfo, processStacks bool) (schema.AtmosConfiguration, error)
+	executeDescribeComponent func(component string, stack string, processTemplates bool, processYamlFunctions bool, skip []string) (map[string]any, error)
+	evaluateYqExpression     func(atmosConfig *schema.AtmosConfiguration, data any, yq string) (any, error)
+}
 
-	query, err := flags.GetString("query")
-	if err != nil {
-		return err
+func NewDescribeComponentExec() *DescribeComponentExec {
+	return &DescribeComponentExec{
+		printOrWriteToFile:       printOrWriteToFile,
+		IsTTYSupportForStdout:    term.IsTTYSupportForStdout,
+		pageCreator:              pager.New(),
+		initCliConfig:            cfg.InitCliConfig,
+		executeDescribeComponent: ExecuteDescribeComponent,
+		evaluateYqExpression:     u.EvaluateYqExpression,
 	}
+}
 
-	skip, err := flags.GetStringSlice("skip")
+func (d *DescribeComponentExec) ExecuteDescribeComponentCmd(describeComponentParams DescribeComponentParams) error {
path: internal/exec/describe_component.go
user: login: github-advanced-security[bot]
body: cyclomatic: function (*DescribeComponentExec).ExecuteDescribeComponentCmd has cyclomatic complexity 11 (> max enabled 10)

[Show more details](https://github.com/cloudposse/atmos/security/code-scanning/891)
created_at: 2025-05-14T20:11:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,125 @@
+package exec
+
+import (
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/stretchr/testify/assert"
+
+	"github.com/cloudposse/atmos/pkg/pager"
+	"github.com/cloudposse/atmos/pkg/schema"
+)
+
+// --- Test ---
path: internal/exec/describe_component_test.go
user: login: github-advanced-security[bot]
body: Comment should end in a period

[Show more details](https://github.com/cloudposse/atmos/security/code-scanning/892)
created_at: 2025-05-14T20:11:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -72,7 +72,7 @@
 }
 
 // HighlightCodeWithConfig highlights the given code using the provided configuration
-func HighlightCodeWithConfig(code string, config schema.AtmosConfiguration, format ...string) (string, error) {
+func HighlightCodeWithConfig(config *schema.AtmosConfiguration, code string, format ...string) (string, error) {
path: pkg/utils/highlight_utils.go
user: login: github-advanced-security[bot]
body: cyclomatic: function HighlightCodeWithConfig has cyclomatic complexity 16 (> max enabled 10)

[Show more details](https://github.com/cloudposse/atmos/security/code-scanning/893)
created_at: 2025-05-14T20:11:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -12,27 +12,31 @@
 )
 
 // PrintAsJSON prints the provided value as JSON document to the console
-func PrintAsJSON(data any) error {
-	j, err := ConvertToJSON(data)
+func PrintAsJSON(atmosConfig *schema.AtmosConfiguration, data any) error {
+	highlighted, err := GetHighlightedJSON(atmosConfig, data)
 	if err != nil {
 		return err
 	}
+	PrintMessage(highlighted)
+	return nil
+}
+
+func GetHighlightedJSON(atmosConfig *schema.AtmosConfiguration, data any) (string, error) {
+	j, err := ConvertToJSON(data)
+	if err != nil {
+		return "", err
+	}
 
 	var prettyJSON bytes.Buffer
 	err = json.Indent(&prettyJSON, []byte(j), "", "  ")
 	if err != nil {
-		return err
+		return "", err
 	}
-
-	atmosConfig := ExtractAtmosConfig(data)
-	highlighted, err := HighlightCodeWithConfig(prettyJSON.String(), atmosConfig)
+	highlighted, err := HighlightCodeWithConfig(atmosConfig, prettyJSON.String())
 	if err != nil {
-		// Fallback to plain text if highlighting fails
-		PrintMessage(prettyJSON.String())
-		return nil
+		return prettyJSON.String(), nil
path: pkg/utils/json_utils.go
user: login: github-advanced-security[bot]
body: error is not nil (line 35) but it returns nil

[Show more details](https://github.com/cloudposse/atmos/security/code-scanning/894)
created_at: 2025-05-14T20:11:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -55,6 +55,8 @@ atmos describe component vpc -s tenant1-ue2-dev --skip=include,eval
 atmos describe component vpc -s plat-ue2-prod --query .vars.tags
 
 atmos describe component vpc -s plat-ue2-prod -q .settings
+
+atmos describe component vpc -s plat-ue2-prod --pager=more
path: website/docs/cli/commands/describe/describe-component.mdx
user: login: Benbentwo
body: `--pager=more` doesn't show the pager, I see `less` and `yes` works. Seems to be part of the schema.go.

```suggestion
atmos describe component vpc -s plat-ue2-prod --pager=yes
```
created_at: 2025-05-14T23:38:46Z
author_association: MEMBER
diff_hunk: @@ -51,3 +61,87 @@
 
 	describeCmd.AddCommand(describeAffectedCmd)
 }
+
+func parseDescribeAffectedCliArgs(cmd *cobra.Command, args []string) (exec.DescribeAffectedCmdArgs, error) {
path: cmd/describe_affected.go
user: login: github-advanced-security[bot]
body: cyclomatic: function parseDescribeAffectedCliArgs has cyclomatic complexity 11 (> max enabled 10)

[Show more details](https://github.com/cloudposse/atmos/security/code-scanning/880)
created_at: 2025-05-15T12:39:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,34 +1,71 @@
 package cmd
 
 import (
+	"errors"
+
 	"github.com/spf13/cobra"
 
 	e "github.com/cloudposse/atmos/internal/exec"
 	u "github.com/cloudposse/atmos/pkg/utils"
 )
 
+var errInvalidFlag = errors.New("invalid arguments. The command requires one argument `component`")
path: cmd/describe_component.go
user: login: github-advanced-security[bot]
body: var `errInvalidFlag` is unused

[Show more details](https://github.com/cloudposse/atmos/security/code-scanning/959)
created_at: 2025-05-15T12:39:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -38,184 +35,83 @@
 	Skip                        []string
 }
 
-func parseDescribeAffectedCliArgs(cmd *cobra.Command, args []string) (DescribeAffectedCmdArgs, error) {
-	info, err := ProcessCommandLineArgs("", cmd, args, nil)
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	atmosConfig, err := cfg.InitCliConfig(info, true)
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-	logger, err := l.NewLoggerFromCliConfig(atmosConfig)
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	err = ValidateStacks(atmosConfig)
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	// Process flags
-	flags := cmd.Flags()
-
-	ref, err := flags.GetString("ref")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	sha, err := flags.GetString("sha")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	repoPath, err := flags.GetString("repo-path")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	format, err := flags.GetString("format")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	if format != "" && format != "yaml" && format != "json" {
-		return DescribeAffectedCmdArgs{}, fmt.Errorf("invalid '--format' flag '%s'. Valid values are 'json' (default) and 'yaml'", format)
-	}
-
-	if format == "" {
-		format = "json"
-	}
-
-	file, err := flags.GetString("file")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	verbose, err := flags.GetBool("verbose")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	sshKeyPath, err := flags.GetString("ssh-key")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	sshKeyPassword, err := flags.GetString("ssh-key-password")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	includeSpaceliftAdminStacks, err := flags.GetBool("include-spacelift-admin-stacks")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	includeDependents, err := flags.GetBool("include-dependents")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	includeSettings, err := flags.GetBool("include-settings")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	upload, err := flags.GetBool("upload")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	cloneTargetRef, err := flags.GetBool("clone-target-ref")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	stack, err := flags.GetString("stack")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	if repoPath != "" && (ref != "" || sha != "" || sshKeyPath != "" || sshKeyPassword != "") {
-		return DescribeAffectedCmdArgs{}, errors.New("if the '--repo-path' flag is specified, the '--ref', '--sha', '--ssh-key' and '--ssh-key-password' flags can't be used")
-	}
-
-	// When uploading, always include dependents and settings for all affected components
-	if upload {
-		includeDependents = true
-		includeSettings = true
-	}
-
-	if verbose {
-		atmosConfig.Logs.Level = u.LogLevelTrace
-		err := logger.SetLogLevel(l.LogLevelTrace)
-		if err != nil {
-			return DescribeAffectedCmdArgs{}, err
-		}
-	}
-
-	query, err := flags.GetString("query")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	processTemplates, err := flags.GetBool("process-templates")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	processYamlFunctions, err := flags.GetBool("process-functions")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	skip, err := flags.GetStringSlice("skip")
-	if err != nil {
-		return DescribeAffectedCmdArgs{}, err
-	}
-
-	result := DescribeAffectedCmdArgs{
-		CLIConfig:                   atmosConfig,
-		CloneTargetRef:              cloneTargetRef,
-		Format:                      format,
-		IncludeDependents:           includeDependents,
-		IncludeSettings:             includeSettings,
-		IncludeSpaceliftAdminStacks: includeSpaceliftAdminStacks,
-		Logger:                      logger,
-		OutputFile:                  file,
-		Ref:                         ref,
-		RepoPath:                    repoPath,
-		SHA:                         sha,
-		SSHKeyPath:                  sshKeyPath,
-		SSHKeyPassword:              sshKeyPassword,
-		Verbose:                     verbose,
-		Upload:                      upload,
-		Stack:                       stack,
-		Query:                       query,
-		ProcessTemplates:            processTemplates,
-		ProcessYamlFunctions:        processYamlFunctions,
-		Skip:                        skip,
-	}
-
-	return result, nil
+type DescribeAffectedExec struct {
+	atmosConfig                               *schema.AtmosConfiguration
+	executeDescribeAffectedWithTargetRepoPath func(
+		atmosConfig schema.AtmosConfiguration,
+		targetRefPath string,
+		verbose bool,
+		includeSpaceliftAdminStacks bool,
+		includeSettings bool,
+		stack string,
+		processTemplates bool,
+		processYamlFunctions bool,
+		skip []string,
+	) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, string, error)
+	executeDescribeAffectedWithTargetRefClone func(
+		atmosConfig schema.AtmosConfiguration,
+		ref string,
+		sha string,
+		sshKeyPath string,
+		sshKeyPassword string,
+		verbose bool,
+		includeSpaceliftAdminStacks bool,
+		includeSettings bool,
+		stack string,
+		processTemplates bool,
+		processYamlFunctions bool,
+		skip []string,
+	) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, string, error)
+	executeDescribeAffectedWithTargetRefCheckout func(
+		atmosConfig schema.AtmosConfiguration,
+		ref string,
+		sha string,
+		verbose bool,
+		includeSpaceliftAdminStacks bool,
+		includeSettings bool,
+		stack string,
+		processTemplates bool,
+		processYamlFunctions bool,
+		skip []string,
+	) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, string, error)
+	addDependentsToAffected func(
+		atmosConfig schema.AtmosConfiguration,
+		affected *[]schema.Affected,
+		includeSettings bool,
+	) error
+	printOrWriteToFile func(
+		atmosConfig *schema.AtmosConfiguration,
+		format string,
+		file string,
+		data any,
+	) error
+	IsTTYSupportForStdout func() bool
+	pageCreator           pager.PageCreator
 }
 
-// ExecuteDescribeAffectedCmd executes `describe affected` command
-func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error {
-	a, err := parseDescribeAffectedCliArgs(cmd, args)
-	if err != nil {
-		return err
+func NewDescribeAffectedExec(
+	atmosConfig *schema.AtmosConfiguration,
+) *DescribeAffectedExec {
+	return &DescribeAffectedExec{
+		atmosConfig: atmosConfig,
+		executeDescribeAffectedWithTargetRepoPath:    ExecuteDescribeAffectedWithTargetRepoPath,
+		executeDescribeAffectedWithTargetRefClone:    ExecuteDescribeAffectedWithTargetRefClone,
+		executeDescribeAffectedWithTargetRefCheckout: ExecuteDescribeAffectedWithTargetRefCheckout,
+		addDependentsToAffected:                      addDependentsToAffected,
+		printOrWriteToFile:                           printOrWriteToFile,
+		IsTTYSupportForStdout:                        term.IsTTYSupportForStdout,
+		pageCreator:                                  pager.New(),
 	}
+}
 
+func (d *DescribeAffectedExec) Execute(a DescribeAffectedCmdArgs) error {
path: internal/exec/describe_affected.go
user: login: github-advanced-security[bot]
body: hugeParam: a is heavy (6120 bytes); consider passing it by pointer

[Show more details](https://github.com/cloudposse/atmos/security/code-scanning/960)
created_at: 2025-05-15T12:39:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -255,70 +151,139 @@
 			a.Skip,
 		)
 	}
-
 	if err != nil {
 		return err
 	}
-
 	// Add dependent components and stacks for each affected component
 	if len(affected) > 0 && a.IncludeDependents {
-		err = addDependentsToAffected(a.CLIConfig, &affected, a.IncludeSettings)
+		err = d.addDependentsToAffected(a.CLIConfig, &affected, a.IncludeSettings)
 		if err != nil {
 			return err
 		}
 	}
 
+	return d.view(a, repoUrl, headHead, baseHead, affected)
+}
+
+func (d *DescribeAffectedExec) view(a DescribeAffectedCmdArgs, repoUrl string, headHead, baseHead *plumbing.Reference, affected []schema.Affected) error {
path: internal/exec/describe_affected.go
user: login: github-advanced-security[bot]
body: hugeParam: a is heavy (6120 bytes); consider passing it by pointer

[Show more details](https://github.com/cloudposse/atmos/security/code-scanning/961)
created_at: 2025-05-15T12:39:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,34 +1,71 @@
 package cmd
 
 import (
+	"errors"
+
 	"github.com/spf13/cobra"
 
 	e "github.com/cloudposse/atmos/internal/exec"
 	u "github.com/cloudposse/atmos/pkg/utils"
 )
 
+var errInvalidFlag = errors.New("invalid arguments. The command requires one argument `component`")
path: cmd/describe_component.go
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Remove unused error variable.**

The `errInvalidFlag` variable is defined but never used in the code, as confirmed by static analysis. Either use this variable or remove it to keep the codebase clean.

```diff
-var errInvalidFlag = errors.New("invalid arguments. The command requires one argument `component`")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion

```

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 golangci-lint (1.64.8)</summary>

[error] 12-12: var `errInvalidFlag` is unused

(unused)

</details>
<details>
<summary>🪛 GitHub Check: golangci-lint</summary>

[failure] 12-12: 
var `errInvalidFlag` is unused

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In cmd/describe_component.go at line 12, the variable errInvalidFlag is defined
but never used. Remove this unused error variable to clean up the codebase and
avoid unnecessary declarations.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-15T12:43:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,34 +1,71 @@
 package cmd
 
 import (
+	"errors"
+
 	"github.com/spf13/cobra"
 
 	e "github.com/cloudposse/atmos/internal/exec"
 	u "github.com/cloudposse/atmos/pkg/utils"
 )
 
+var errInvalidFlag = errors.New("invalid arguments. The command requires one argument `component`")
+
 // describeComponentCmd describes configuration for components
 var describeComponentCmd = &cobra.Command{
 	Use:                "component",
 	Short:              "Show configuration details for an Atmos component in a stack",
 	Long:               `Display the configuration details for a specific Atmos component within a designated Atmos stack, including its dependencies, settings, and overrides.`,
 	FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
-	Run: func(cmd *cobra.Command, args []string) {
+	Args:               cobra.ExactArgs(1),
+	RunE: func(cmd *cobra.Command, args []string) error {
 		// Check Atmos configuration
 		checkAtmosConfig()
 
-		err := e.ExecuteDescribeComponentCmd(cmd, args)
+		flags := cmd.Flags()
+
+		stack, err := flags.GetString("stack")
+		checkFlagNotPresentError(err)
+		format, err := flags.GetString("format")
+		checkFlagNotPresentError(err)
+		file, err := flags.GetString("file")
+		checkFlagNotPresentError(err)
+		processTemplates, err := flags.GetBool("process-templates")
+		checkFlagNotPresentError(err)
+		processYamlFunctions, err := flags.GetBool("process-functions")
+		checkFlagNotPresentError(err)
+		query, err := flags.GetString("query")
+		checkFlagNotPresentError(err)
+		skip, err := flags.GetStringSlice("skip")
+		checkFlagNotPresentError(err)
+		pager, err := flags.GetString("pager")
+		checkFlagNotPresentError(err)
path: cmd/describe_component.go
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add documentation for the pager flag.**

The pager flag is retrieved and used, but lacks documentation in the `init()` function like other flags have.

```diff
describeComponentCmd.PersistentFlags().StringSlice("skip", nil, "Skip executing a YAML function in the Atmos stack manifests when executing the command")
+describeComponentCmd.PersistentFlags().String("pager", "", "Specify the pager to use for output")

err := describeComponentCmd.MarkPersistentFlagRequired("stack")
```

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In cmd/describe_component.go around lines 41 to 42, the pager flag is retrieved
but lacks documentation in the init() function. Add a descriptive comment for
the pager flag in the init() function, similar to how other flags are
documented, explaining its purpose and usage to improve code clarity and
maintainability.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T12:43:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,55 @@
+package exec
+
+import (
+	"testing"
+
+	"github.com/cloudposse/atmos/pkg/pager"
+	"github.com/cloudposse/atmos/pkg/schema"
+	"github.com/go-git/go-git/v5/plumbing"
+	"github.com/golang/mock/gomock"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestDescribeAffected(t *testing.T) {
+	d := NewDescribeAffectedExec(&schema.AtmosConfiguration{})
+	d.IsTTYSupportForStdout = func() bool {
+		return false
+	}
+	d.executeDescribeAffectedWithTargetRepoPath = func(atmosConfig schema.AtmosConfiguration, targetRefPath string, verbose, includeSpaceliftAdminStacks, includeSettings bool, stack string, processTemplates, processYamlFunctions bool, skip []string) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, string, error) {
+		return []schema.Affected{}, nil, nil, "", nil
+	}
+	d.executeDescribeAffectedWithTargetRefClone = func(atmosConfig schema.AtmosConfiguration, ref, sha, sshKeyPath, sshKeyPassword string, verbose, includeSpaceliftAdminStacks, includeSettings bool, stack string, processTemplates, processYamlFunctions bool, skip []string) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, string, error) {
+		return []schema.Affected{}, nil, nil, "", nil
+	}
+	d.executeDescribeAffectedWithTargetRefCheckout = func(atmosConfig schema.AtmosConfiguration, ref, sha string, verbose, includeSpaceliftAdminStacks, includeSettings bool, stack string, processTemplates, processYamlFunctions bool, skip []string) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, string, error) {
+		return []schema.Affected{}, nil, nil, "", nil
+	}
+
+	err := d.Execute(DescribeAffectedCmdArgs{
+		Format:   "json",
+		RepoPath: "",
+	})
+	assert.NoError(t, err)
+	err = d.Execute(DescribeAffectedCmdArgs{
+		Format:         "yaml",
+		CloneTargetRef: true,
+	})
+	assert.NoError(t, err)
+
+	d.IsTTYSupportForStdout = func() bool {
+		return true
+	}
+	ctrl := gomock.NewController(t)
+	mockPager := pager.NewMockPageCreator(ctrl)
+	mockPager.EXPECT().Run(gomock.Any(), gomock.Any()).Return(nil)
+	d.pageCreator = mockPager
path: internal/exec/describe_affected_test.go
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add `defer ctrl.Finish()` to guarantee gomock expectations are asserted**

Without explicitly finishing the controller the test may silently pass even when expectations are unmet.  
Just add a single `defer ctrl.Finish()` right after the controller is created.

```diff
 ctrl := gomock.NewController(t)
+defer ctrl.Finish()
 mockPager := pager.NewMockPageCreator(ctrl)
```

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In internal/exec/describe_affected_test.go around lines 42 to 45, the gomock
controller is created but not explicitly finished, which can cause the test to
pass silently even if expectations are unmet. Add a line `defer ctrl.Finish()`
immediately after creating the controller to ensure gomock expectations are
properly asserted at the end of the test.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-15T12:43:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -51,3 +61,87 @@
 
 	describeCmd.AddCommand(describeAffectedCmd)
 }
+
+func parseDescribeAffectedCliArgs(cmd *cobra.Command, args []string) (exec.DescribeAffectedCmdArgs, error) {
+	var atmosConfig schema.AtmosConfiguration
+	if info, err := exec.ProcessCommandLineArgs("", cmd, args, nil); err != nil {
+		return exec.DescribeAffectedCmdArgs{}, err
+	} else if atmosConfig, err = cfg.InitCliConfig(info, true); err != nil {
+		return exec.DescribeAffectedCmdArgs{}, err
+	}
+
+	err := exec.ValidateStacks(atmosConfig)
+	if err != nil {
+		return exec.DescribeAffectedCmdArgs{}, err
+	}
+
+	// Process flags
+	flags := cmd.Flags()
+
+	result := exec.DescribeAffectedCmdArgs{
+		CLIConfig: atmosConfig,
+	}
+	setFlagValueInCliArgs(flags, &result)
+
+	if result.Format != "yaml" && result.Format != "json" {
+		return exec.DescribeAffectedCmdArgs{}, exec.ErrInvalidFormat
+	}
+	if result.RepoPath != "" && (result.Ref != "" || result.SHA != "" || result.SSHKeyPath != "" || result.SSHKeyPassword != "") {
+		return exec.DescribeAffectedCmdArgs{}, ErrRepoPathConflict
+	}
+
+	return result, nil
+}
+
+func setFlagValueInCliArgs(flags *pflag.FlagSet, describe *exec.DescribeAffectedCmdArgs) {
+	flagsKeyValue := map[string]any{
+		"ref":                            &describe.Ref,
+		"sha":                            &describe.SHA,
+		"repo-path":                      &describe.RepoPath,
+		"ssh-key":                        &describe.SSHKeyPath,
+		"ssh-key-password":               &describe.SSHKeyPassword,
+		"include-spacelift-admin-stacks": &describe.IncludeSpaceliftAdminStacks,
+		"include-dependents":             &describe.IncludeDependents,
+		"include-settings":               &describe.IncludeSettings,
+		"upload":                         &describe.Upload,
+		"clone-target-ref":               &describe.CloneTargetRef,
+		"process-templates":              &describe.ProcessTemplates,
+		"process-functions":              &describe.ProcessYamlFunctions,
+		"skip":                           &describe.Skip,
+		"pager":                          &describe.CLIConfig.Settings.Terminal.Pager,
+		"stack":                          &describe.Stack,
+		"format":                         &describe.Format,
+		"file":                           &describe.OutputFile,
+		"query":                          &describe.Query,
+	}
+
+	var err error
+	for k := range flagsKeyValue {
+		if !flags.Changed(k) {
+			continue
+		}
+		switch v := flagsKeyValue[k].(type) {
+		case *string:
+			*v, err = flags.GetString(k)
+		case *bool:
+			*v, err = flags.GetBool(k)
+		default:
+			panic(fmt.Sprintf("unsupported type %T for flag %s", v, k))
+		}
path: cmd/describe_affected.go
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**`--skip` flag panics – support `StringSlice` instead of crashing**

`setFlagValueInCliArgs` only handles `*string` and `*bool`.  
When `--skip` is supplied (`[]string`), the `default` arm is hit and the CLI panics.

```diff
@@ switch v := flagsKeyValue[k].(type) {
 case *string:
     *v, err = flags.GetString(k)
 case *bool:
     *v, err = flags.GetBool(k)
+case *[]string:
+    *v, err = flags.GetStringSlice(k)
 default:
     panic(fmt.Sprintf("unsupported type %T for flag %s", v, k))
 }
```

Consider returning an error instead of panicking for unexpected types to keep the CLI resilient.



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
		switch v := flagsKeyValue[k].(type) {
		case *string:
			*v, err = flags.GetString(k)
		case *bool:
			*v, err = flags.GetBool(k)
		case *[]string:
			*v, err = flags.GetStringSlice(k)
		default:
			panic(fmt.Sprintf("unsupported type %T for flag %s", v, k))
		}
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In cmd/describe_affected.go around lines 123 to 130, the switch statement panics
when encountering a flag of type StringSlice like the --skip flag, because only
*string and *bool types are handled. To fix this, add a case to handle the
StringSlice type properly by retrieving the string slice from flags and
assigning it. Also, replace the panic in the default case with returning an
error indicating the unsupported flag type to prevent the CLI from crashing and
improve resilience.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-15T12:43:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -255,70 +151,139 @@
 			a.Skip,
 		)
 	}
-
 	if err != nil {
 		return err
 	}
-
 	// Add dependent components and stacks for each affected component
 	if len(affected) > 0 && a.IncludeDependents {
-		err = addDependentsToAffected(a.CLIConfig, &affected, a.IncludeSettings)
+		err = d.addDependentsToAffected(a.CLIConfig, &affected, a.IncludeSettings)
 		if err != nil {
 			return err
 		}
 	}
 
+	return d.view(a, repoUrl, headHead, baseHead, affected)
+}
+
+func (d *DescribeAffectedExec) view(a DescribeAffectedCmdArgs, repoUrl string, headHead, baseHead *plumbing.Reference, affected []schema.Affected) error {
 	if a.Query == "" {
-		a.Logger.Trace("\nAffected components and stacks: \n")
+		if err := d.uploadableQuery(&a, repoUrl, headHead, baseHead, affected); err != nil {
+			return err
+		}
+	} else {
+		res, err := u.EvaluateYqExpression(d.atmosConfig, affected, a.Query)
+		if err != nil {
+			return err
+		}
 
-		err = printOrWriteToFile(a.Format, a.OutputFile, affected)
+		err = viewWithScroll(&viewWithScrollProps{pager.New(), term.IsTTYSupportForStdout, d.printOrWriteToFile, d.atmosConfig, "Affected components and stacks", a.Format, a.OutputFile, res})
 		if err != nil {
path: internal/exec/describe_affected.go
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Respect injected pager – use `d.pageCreator` instead of a fresh instance**

Creating a new pager here bypasses the injected mock, making tests brittle and blocking future DI.  
Swap in the executor’s pager:

```diff
-        err = viewWithScroll(&viewWithScrollProps{pager.New(), term.IsTTYSupportForStdout, d.printOrWriteToFile, d.atmosConfig, "Affected components and stacks", a.Format, a.OutputFile, res})
+        err = viewWithScroll(&viewWithScrollProps{d.pageCreator, d.IsTTYSupportForStdout, d.printOrWriteToFile, d.atmosConfig, "Affected components and stacks", a.Format, a.OutputFile, res})
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
        err = viewWithScroll(&viewWithScrollProps{d.pageCreator, d.IsTTYSupportForStdout, d.printOrWriteToFile, d.atmosConfig, "Affected components and stacks", a.Format, a.OutputFile, res})
        if err != nil {
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In internal/exec/describe_affected.go at lines 179-180, replace the direct
creation of a new pager instance with the injected pager from d.pageCreator to
respect dependency injection and enable proper mocking in tests. Modify the call
to viewWithScrollProps to use d.pageCreator instead of pager.New(), ensuring the
existing pager instance is used rather than creating a fresh one.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-15T12:43:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,34 +1,71 @@
 package cmd
 
 import (
+	"errors"
+
 	"github.com/spf13/cobra"
 
 	e "github.com/cloudposse/atmos/internal/exec"
 	u "github.com/cloudposse/atmos/pkg/utils"
 )
 
+var errInvalidFlag = errors.New("invalid arguments. The command requires one argument `component`")
path: cmd/describe_component.go
user: login: Benbentwo
body: ```suggestion
```
created_at: 2025-05-15T12:44:09Z
author_association: MEMBER
diff_hunk: @@ -55,6 +55,8 @@ atmos describe component vpc -s tenant1-ue2-dev --skip=include,eval
 atmos describe component vpc -s plat-ue2-prod --query .vars.tags
 
 atmos describe component vpc -s plat-ue2-prod -q .settings
+
+atmos describe component vpc -s plat-ue2-prod --pager=more
path: website/docs/cli/commands/describe/describe-component.mdx
user: login: samtholiya
body: `more` is to disable and since pager is default behavior, the intent here was to show that pager argument existed.

having a pager with yes arg does not make sense.
created_at: 2025-05-15T21:47:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,34 +1,71 @@
 package cmd
 
 import (
+	"errors"
+
 	"github.com/spf13/cobra"
 
 	e "github.com/cloudposse/atmos/internal/exec"
 	u "github.com/cloudposse/atmos/pkg/utils"
 )
 
+var errInvalidFlag = errors.New("invalid arguments. The command requires one argument `component`")
+
 // describeComponentCmd describes configuration for components
 var describeComponentCmd = &cobra.Command{
 	Use:                "component",
 	Short:              "Show configuration details for an Atmos component in a stack",
 	Long:               `Display the configuration details for a specific Atmos component within a designated Atmos stack, including its dependencies, settings, and overrides.`,
 	FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
-	Run: func(cmd *cobra.Command, args []string) {
+	Args:               cobra.ExactArgs(1),
+	RunE: func(cmd *cobra.Command, args []string) error {
 		// Check Atmos configuration
 		checkAtmosConfig()
 
-		err := e.ExecuteDescribeComponentCmd(cmd, args)
+		flags := cmd.Flags()
+
+		stack, err := flags.GetString("stack")
+		checkFlagNotPresentError(err)
+		format, err := flags.GetString("format")
+		checkFlagNotPresentError(err)
+		file, err := flags.GetString("file")
+		checkFlagNotPresentError(err)
+		processTemplates, err := flags.GetBool("process-templates")
+		checkFlagNotPresentError(err)
+		processYamlFunctions, err := flags.GetBool("process-functions")
+		checkFlagNotPresentError(err)
+		query, err := flags.GetString("query")
+		checkFlagNotPresentError(err)
+		skip, err := flags.GetStringSlice("skip")
+		checkFlagNotPresentError(err)
+		pager, err := flags.GetString("pager")
+		checkFlagNotPresentError(err)
path: cmd/describe_component.go
user: login: samtholiya
body: we already have it added to the describe command perrsistent flags so this is not required
created_at: 2025-05-15T21:52:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,34 +1,71 @@
 package cmd
 
 import (
+	"errors"
+
 	"github.com/spf13/cobra"
 
 	e "github.com/cloudposse/atmos/internal/exec"
 	u "github.com/cloudposse/atmos/pkg/utils"
 )
 
+var errInvalidFlag = errors.New("invalid arguments. The command requires one argument `component`")
+
 // describeComponentCmd describes configuration for components
 var describeComponentCmd = &cobra.Command{
 	Use:                "component",
 	Short:              "Show configuration details for an Atmos component in a stack",
 	Long:               `Display the configuration details for a specific Atmos component within a designated Atmos stack, including its dependencies, settings, and overrides.`,
 	FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
-	Run: func(cmd *cobra.Command, args []string) {
+	Args:               cobra.ExactArgs(1),
+	RunE: func(cmd *cobra.Command, args []string) error {
 		// Check Atmos configuration
 		checkAtmosConfig()
 
-		err := e.ExecuteDescribeComponentCmd(cmd, args)
+		flags := cmd.Flags()
+
+		stack, err := flags.GetString("stack")
+		checkFlagNotPresentError(err)
+		format, err := flags.GetString("format")
+		checkFlagNotPresentError(err)
+		file, err := flags.GetString("file")
+		checkFlagNotPresentError(err)
+		processTemplates, err := flags.GetBool("process-templates")
+		checkFlagNotPresentError(err)
+		processYamlFunctions, err := flags.GetBool("process-functions")
+		checkFlagNotPresentError(err)
+		query, err := flags.GetString("query")
+		checkFlagNotPresentError(err)
+		skip, err := flags.GetStringSlice("skip")
+		checkFlagNotPresentError(err)
+		pager, err := flags.GetString("pager")
+		checkFlagNotPresentError(err)
path: cmd/describe_component.go
user: login: coderabbitai[bot]
body: @samtholiya I understand - if the pager flag is already added to the describe command's persistent flags, then it would be inherited by the describeComponentCmd automatically through Cobra's flag inheritance mechanism. No need to add it again. Thanks for the clarification!


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer>@samtholiya I understand - if the pager flag is already added to the describe command's persistent flags, then it would be inherited by the describeComponentCmd automatically through Cobra's flag inheritance mechanism. No need to add it again. Thanks for the clarification!</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T21:54:32Z
author_association: CONTRIBUTOR

PR comments:
user: login: mergify[bot]
created_at: 2025-04-24T19:45:26Z
body: 💥 This pull request now has conflicts. Could you fix it @samtholiya? 🙏
author_association: NONE
user: login: mergify[bot]
created_at: 2025-04-25T20:55:25Z
body: 💥 This pull request now has conflicts. Could you fix it @samtholiya? 🙏
author_association: NONE
user: login: codecov[bot]
created_at: 2025-04-25T21:21:00Z
body: ## [Codecov](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) Report
Attention: Patch coverage is `71.33333%` with `43 lines` in your changes missing coverage. Please review.
> Project coverage is 48.31%. Comparing base [(`a55467b`)](https://app.codecov.io/gh/cloudposse/atmos/commit/a55467bd18deac8e73ac1675a319d2e731643e46?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) to head [(`2606f33`)](https://app.codecov.io/gh/cloudposse/atmos/commit/2606f33601cb041476ec2337271a8428b4690af7?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse).
> Report is 1 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) | Patch % | Lines |
|---|---|---|
| [internal/exec/describe\_component.go](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&filepath=internal%2Fexec%2Fdescribe_component.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse#diff-aW50ZXJuYWwvZXhlYy9kZXNjcmliZV9jb21wb25lbnQuZ28=) | 78.78% | [10 Missing and 4 partials :warning: ](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) |
| [internal/exec/describe\_affected.go](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&filepath=internal%2Fexec%2Fdescribe_affected.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse#diff-aW50ZXJuYWwvZXhlYy9kZXNjcmliZV9hZmZlY3RlZC5nbw==) | 0.00% | [10 Missing :warning: ](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) |
| [pkg/utils/json\_utils.go](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&filepath=pkg%2Futils%2Fjson_utils.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse#diff-cGtnL3V0aWxzL2pzb25fdXRpbHMuZ28=) | 57.14% | [5 Missing and 1 partial :warning: ](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) |
| [cmd/describe\_component.go](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&filepath=cmd%2Fdescribe_component.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse#diff-Y21kL2Rlc2NyaWJlX2NvbXBvbmVudC5nbw==) | 87.80% | [3 Missing and 2 partials :warning: ](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) |
| [internal/exec/atmos.go](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&filepath=internal%2Fexec%2Fatmos.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse#diff-aW50ZXJuYWwvZXhlYy9hdG1vcy5nbw==) | 0.00% | [2 Missing :warning: ](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) |
| [pkg/utils/highlight\_utils.go](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&filepath=pkg%2Futils%2Fhighlight_utils.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse#diff-cGtnL3V0aWxzL2hpZ2hsaWdodF91dGlscy5nbw==) | 33.33% | [2 Missing :warning: ](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) |
| [internal/exec/atlantis\_generate\_repo\_config.go](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&filepath=internal%2Fexec%2Fatlantis_generate_repo_config.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse#diff-aW50ZXJuYWwvZXhlYy9hdGxhbnRpc19nZW5lcmF0ZV9yZXBvX2NvbmZpZy5nbw==) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) |
| [internal/exec/describe\_dependents.go](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&filepath=internal%2Fexec%2Fdescribe_dependents.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse#diff-aW50ZXJuYWwvZXhlYy9kZXNjcmliZV9kZXBlbmRlbnRzLmdv) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) |
| [internal/exec/describe\_stacks.go](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&filepath=internal%2Fexec%2Fdescribe_stacks.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse#diff-aW50ZXJuYWwvZXhlYy9kZXNjcmliZV9zdGFja3MuZ28=) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) |
| [internal/exec/describe\_workflows.go](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&filepath=internal%2Fexec%2Fdescribe_workflows.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse#diff-aW50ZXJuYWwvZXhlYy9kZXNjcmliZV93b3JrZmxvd3MuZ28=) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) |

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##             main    #1215       +/-   ##
===========================================
+ Coverage   35.39%   48.31%   +12.91%     
===========================================
  Files         232      232               
  Lines       25255    25329       +74     
===========================================
+ Hits         8940    12237     +3297     
+ Misses      15043    11494     -3549     
- Partials     1272     1598      +326     
```

| [Flag](https://app.codecov.io/gh/cloudposse/atmos/pull/1215/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) | Coverage Δ | |
|---|---|---|
| [unittests](https://app.codecov.io/gh/cloudposse/atmos/pull/1215/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse) | `48.31% <71.33%> (+12.91%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/cloudposse/atmos/pull/1215?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudposse).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: mergify[bot]
created_at: 2025-04-27T14:46:28Z
body: > [!IMPORTANT]
> #### Cloud Posse Engineering Team Review Required
> This pull request modifies files that require Cloud Posse's review. Please be patient, and a core maintainer will review your changes.
>
> To expedite this process, reach out to us on [Slack](https://cloudposse.com/slack) in the `#pr-reviews` channel.
author_association: NONE
user: login: mergify[bot]
created_at: 2025-04-27T14:52:13Z
body: 💥 This pull request now has conflicts. Could you fix it @samtholiya? 🙏
author_association: NONE
user: login: mergify[bot]
created_at: 2025-05-02T18:41:54Z
body: 💥 This pull request now has conflicts. Could you fix it @samtholiya? 🙏
author_association: NONE
user: login: mergify[bot]
created_at: 2025-05-13T22:18:51Z
body: 💥 This pull request now has conflicts. Could you fix it @samtholiya? 🙏
author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-05-13T22:27:44Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

<details>
<summary>📝 Walkthrough</summary>

## Walkthrough

This update refactors the output and paging logic for several `describe` commands, notably `describe component` and `describe config`, introducing a native pager interface with syntax highlighting. Output functions now accept a pointer to the configuration, and CLI/test code is updated accordingly. Documentation and tests reflect the new pager flag and behaviors.

## Changes

| Files/Group                                                                                  | Change Summary                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
|---------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `cmd/describe_component.go`                                                                 | Refactored to use `RunE`, enforced exact argument count, improved flag error handling, and switched to structured parameter passing for execution. Added helper for flag error checks.                                                                                                         |
| `cmd/describe_affected.go`                                                                  | Refactored to parse and validate CLI args explicitly, enforce mutual exclusivity of flags, removed verbose flag, and separated argument parsing from execution. Added error for repo path conflicts and structured CLI args handling.                                                                                                         |
| `internal/exec/describe_component.go`, `internal/exec/describe_config.go`                   | Refactored command execution into executor structs with injected dependencies. Added native pager integration, syntax highlighting, modularized output, and improved error handling. Parameterized inputs and separated flag parsing from execution.                                           |
| `internal/exec/describe_affected.go`, `internal/exec/describe_dependents.go`,               | Updated output functions to accept configuration pointer as first argument. No logic changes.                                                                                                                                                                                                                                         |
| `internal/exec/describe_stacks.go`, `internal/exec/describe_workflows.go`,                  | Same as above: updated output function calls for new signature.                                                                                                                                                                                                                                                                                                               |
| `internal/exec/atlantis_generate_repo_config.go`, `internal/exec/atmos.go`                  | Updated calls to `PrintAsYAML` to include configuration pointer.                                                                                                                                                                                                                                                                                                              |
| `internal/exec/file_utils.go`                                                               | Changed `printOrWriteToFile` to accept configuration pointer and pass it to output utilities.                                                                                                                                                                                                                                          |
| `internal/exec/describe_component_test.go`, `internal/exec/describe_config_test.go`, `internal/exec/describe_affected_test.go` | Added and updated tests for executor logic, pager usage, output formats, and error conditions. Used mocks for pager and output.                                                                                                                                                                                        |
| `pkg/utils/yaml_utils.go`, `pkg/utils/json_utils.go`                                        | Refactored `PrintAsYAML` and `PrintAsJSON` to accept configuration pointer, added helpers for highlighted output, improved error handling, and adjusted parameter order.                                                                                                                        |
| `pkg/utils/highlight_utils.go`                                                              | Updated highlighting functions to accept configuration pointer and adjusted internal calls.                                                                                                                                                                                                                                            |
| `pkg/utils/yq_test.go`, `pkg/atlantis/atlantis_generate_repo_config_test.go`                | Updated tests to use new output function signatures.                                                                                                                                                                                                                                            |
| `pkg/utils/json_utils_test.go`                                                              | Added test for `PrintAsJSON` with configuration.                                                                                                                                                                                                                                               |
| `tests/cli_describe_component_test.go`, `tests/describe_test.go`                            | Added CLI integration tests for `describe component` with pager and output format options.                                                                                                                                                                                                      |
| `Makefile`                                                                                  | Updated `testacc-cover` to include `-coverpkg=./...` for full coverage analysis.                                                                                                                                                                                                                |
| `website/docs/cli/commands/describe/describe-component.mdx`                                 | Documented new `--pager` flag and provided example usage.                                                                                                                                                                                                                                       |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant CLI
    participant Executor
    participant Pager
    participant Output

    User->>CLI: Run 'atmos describe component ... --pager ...'
    CLI->>Executor: Parse flags and args, build params
    Executor->>Executor: Execute describe logic
    Executor->>Output: Prepare output (YAML/JSON)
    alt Pager enabled and TTY supported
        Executor->>Pager: Display output with highlighting
        Pager->>User: Show paged, highlighted content
    else
        Output->>User: Print/write output directly
    end
```

## Assessment against linked issues

| Objective                                                                                          | Addressed | Explanation                                                                                       |
|----------------------------------------------------------------------------------------------------|-----------|---------------------------------------------------------------------------------------------------|
| Implement native pager for all `atmos describe` commands and `--help` commands (DEV-2958)          | ✅        |                                                                                                   |
| Pager should only load if content exceeds max TTY height (DEV-2958)                                | ❓        | Pager integration present, but content-length-based loading logic is not clearly shown.            |
| Pager should support forcing color via config or ENV (DEV-2958)                                    | ✅        |                                                                                                   |

## Possibly related PRs

- #714: Adds a `--stack` flag to `describe affected` command and updates internal filtering, related by overlapping CLI and execution code changes.
- #1203: Adds pager support to `describe config` command, related by shared pager implementation but different command focus.
- #1236: Refactors `describeAffectedCmd` with structured execution and pager support, directly related to this PR's changes.

## Suggested reviewers

- osterman  
- aknysh

</details>

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!NOTE]
> <details>
> <summary>⚡️ AI Code Reviews for VS Code, Cursor, Windsurf</summary>
> 
> CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
> Learn more [here](http://coderabbit.ai/ide).
> 
> </details>

---

> [!NOTE]
> <details>
> <summary>⚡️ Faster reviews with caching</summary>
> 
> CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure `Review - Disable Cache` at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the `Data Retention` setting under your Organization Settings.
> Enjoy the performance boost—your workflow just got faster.
> 
> </details>

<!-- announcements_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=cloudposse/atmos&utm_content=1215):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` or `@auto-summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` or `@auto-title` anywhere in the PR title to generate the title automatically.

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: mergify[bot]
created_at: 2025-05-14T21:18:36Z
body: 💥 This pull request now has conflicts. Could you fix it @samtholiya? 🙏
author_association: NONE
user: login: mergify[bot]
created_at: 2025-05-15T12:37:21Z
body: > [!WARNING]
> #### This PR exceeds the recommended limit of 1,000 lines.
>
> Large PRs are difficult to review and may be rejected due to their size.
>
> Please verify that this PR does not address multiple issues.
> Consider refactoring it into smaller, more focused PRs to facilitate a smoother review process.
author_association: NONE
user: login: mergify[bot]
created_at: 2025-05-15T16:31:16Z
body: 💥 This pull request now has conflicts. Could you fix it @samtholiya? 🙏
author_association: NONE
user: login: mergify[bot]
created_at: 2025-05-15T21:45:43Z
body: 💥 This pull request now has conflicts. Could you fix it @samtholiya? 🙏
author_association: NONE