From bfcf227845586dd2d6b5784ffee1c9dfa29fe2ba Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 23:40:09 +0000 Subject: [PATCH 1/2] Initial plan From 30f9951a23ef2c2ac89562e9fe4cc28cd913bb34 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 23:59:59 +0000 Subject: [PATCH 2/2] docs: document 21 undocumented console exports and fix StripANSI reference in AGENTS.md Agent-Logs-Url: https://github.com/github/gh-aw/sessions/227f441a-3020-4a42-ab3b-68614001b640 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- AGENTS.md | 2 +- pkg/console/README.md | 231 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index edfc2d42f4f..a342db0edc6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -858,7 +858,7 @@ npm view @github/copilot 2>&1 | cat | tee output.txt ``` **Prevention layers:** -1. **Compiler sanitization**: The workflow compiler (`pkg/workflow/compiler_yaml.go`) automatically strips ANSI codes from descriptions, sources, and comments using `stringutil.StripANSIEscapeCodes()` +1. **Compiler sanitization**: The workflow compiler (`pkg/workflow/compiler_yaml.go`) automatically strips ANSI codes from descriptions, sources, and comments using `stringutil.StripANSI()` 2. **CI validation**: The `validate-yaml` job in `.github/workflows/ci.yml` scans all YAML files for ANSI escape sequences before other jobs run 3. **Detection command**: Run `find .github/workflows -name "*.yml" -o -name "*.yaml" | xargs grep -P '\x1b\[[0-9;]*[a-zA-Z]'` to check for ANSI codes diff --git a/pkg/console/README.md b/pkg/console/README.md index a313eea0124..79c690e8722 100644 --- a/pkg/console/README.md +++ b/pkg/console/README.md @@ -325,7 +325,10 @@ All `Format*` functions return a styled string ready to be printed to `os.Stderr | `FormatPromptMessage(message string) string` | Cyan | Interactive prompt labels | | `FormatVerboseMessage(message string) string` | Muted/comment | Verbose/debug detail | | `FormatListItem(item string) string` | Foreground | Individual list entries | +| `FormatListHeader(header string) string` | Plain (WASM only) | Section headers inside lists | | `FormatSectionHeader(header string) string` | Bold, bordered | Section titles in output | +| `FormatLocationMessage(message string) string` | Foreground (WASM only) | File and location paths | +| `FormatCountMessage(message string) string` | Foreground (WASM only) | Counts and metrics | ### Usage Pattern @@ -414,6 +417,21 @@ table := console.RenderTable(console.TableConfig{ fmt.Print(table) ``` +### `RenderTree(root TreeNode) string` + +Renders a `TreeNode` hierarchy as an indented tree string. + +```go +tree := console.RenderTree(console.TreeNode{ + Value: "root", + Children: []console.TreeNode{ + {Value: "child1"}, + {Value: "child2", Children: []console.TreeNode{{Value: "grandchild"}}}, + }, +}) +fmt.Print(tree) +``` + ## Types ### `CompilerError` @@ -513,6 +531,183 @@ if err != nil || !confirmed { > **Note**: `ConfirmAction` is only available in non-WASM builds. In WASM environments the function is unavailable. +### `ShowInteractiveList(title string, items []ListItem) (string, error)` + +Displays an interactive single-selection list using arrow key navigation. Returns the value of the selected `ListItem`. Returns an error if the list is empty or the prompt is cancelled. Falls back to a numbered text list in non-TTY environments. + +```go +items := []console.ListItem{ + console.NewListItem("Option A", "First choice", "a"), + console.NewListItem("Option B", "Second choice", "b"), +} +selected, err := console.ShowInteractiveList("Pick one", items) +``` + +### `PromptInput(title, description, placeholder string) (string, error)` + +Displays a single-line text input prompt. Returns the entered string or an error. + +```go +value, err := console.PromptInput("Repository name", "Enter the full owner/repo", "owner/repo") +``` + +> **Note**: `PromptInput` is only available in WASM builds. Use `huh` forms directly in non-WASM builds. + +### `PromptSecretInput(title, description string) (string, error)` + +Displays a masked password/secret input prompt. The entered value is hidden as the user types. Returns the entered secret or an error. + +```go +token, err := console.PromptSecretInput("GitHub Token", "Enter your personal access token") +``` + +> **Note**: In non-WASM builds this requires a TTY on stderr; in WASM builds it always returns an error. + +### `PromptInputWithValidation(title, description, placeholder string, validate func(string) error) (string, error)` + +Like `PromptInput` but accepts a validation function that is called on the entered value before the form is submitted. + +```go +value, err := console.PromptInputWithValidation( + "Workflow name", "Must be kebab-case", "my-workflow", + func(s string) error { + if s == "" { + return errors.New("name cannot be empty") + } + return nil + }, +) +``` + +> **Note**: `PromptInputWithValidation` is only available in WASM builds. + +### `PromptSelect(title, description string, options []SelectOption) (string, error)` + +Displays a single-select dropdown prompt. Returns the `Value` of the chosen `SelectOption` or an error. + +```go +opt, err := console.PromptSelect( + "Engine", "Choose an AI engine", + []console.SelectOption{ + {Label: "Copilot", Value: "copilot"}, + {Label: "Claude", Value: "claude"}, + }, +) +``` + +> **Note**: `PromptSelect` is only available in WASM builds. + +### `PromptMultiSelect(title, description string, options []SelectOption, limit int) ([]string, error)` + +Displays a multi-select prompt. Returns a slice of selected `Value` strings or an error. Pass `limit ≤ 0` for no selection limit. + +```go +selected, err := console.PromptMultiSelect( + "Toolsets", "Choose toolsets to enable", + []console.SelectOption{ + {Label: "Default", Value: "default"}, + {Label: "Issues", Value: "issues"}, + {Label: "PRs", Value: "pull_requests"}, + }, + 0, +) +``` + +> **Note**: `PromptMultiSelect` is only available in WASM builds. + +### `RunForm(fields []FormField) error` + +Runs a multi-field interactive form defined by a slice of `FormField` values. Populates the `Value` pointer of each field and returns an error if the form is cancelled or fails. + +```go +var name, token string +err := console.RunForm([]console.FormField{ + {Type: "input", Title: "Name", Value: &name}, + {Type: "password", Title: "Token", Value: &token}, +}) +``` + +> **Note**: `RunForm` is only available in WASM builds. Use `huh` forms directly in non-WASM builds. + +## Layout Functions + +These functions compose styled sections for terminal output. They are available only in WASM builds; non-WASM code should use the `RenderTitleBox`, `RenderInfoSection`, and `RenderComposedSections` functions instead. + +### `LayoutTitleBox(title string, width int) string` + +Returns a title box string of at least `width` characters containing `title`. + +```go +header := console.LayoutTitleBox("Audit Report", 60) +fmt.Fprintln(os.Stderr, header) +``` + +### `LayoutInfoSection(label, value string) string` + +Returns a formatted `label: value` line with consistent indentation. + +```go +line := console.LayoutInfoSection("Repository", "github/gh-aw") +fmt.Fprintln(os.Stderr, line) +``` + +### `LayoutEmphasisBox(content string, color any) string` + +Returns `content` wrapped in an emphasis box. The `color` parameter is reserved for future use (for example, to pass a `lipgloss.Color` value) and is currently ignored by the WASM implementation. + +```go +box := console.LayoutEmphasisBox("Important notice", nil) +fmt.Fprintln(os.Stderr, box) +``` + +### `LayoutJoinVertical(sections ...string) string` + +Joins multiple rendered section strings with newlines. + +```go +output := console.LayoutJoinVertical(header, body, footer) +fmt.Fprintln(os.Stderr, output) +``` + +## Terminal Control Functions + +These functions emit ANSI control sequences to manage the terminal display. They are no-ops when stderr is not a TTY. + +### `ClearScreen()` + +Clears the terminal screen and moves the cursor to the home position. + +```go +console.ClearScreen() +``` + +### `ClearLine()` + +Clears the current terminal line (moves to start of line and erases to end). + +```go +console.ClearLine() +fmt.Fprint(os.Stderr, "Updated status...") +``` + +### `ShowWelcomeBanner(description string)` + +Clears the screen and displays the `gh aw` welcome banner followed by `description`. Use at the start of interactive commands for a consistent onboarding experience. + +```go +console.ShowWelcomeBanner("Let's create your first agentic workflow.") +``` + +## Verbose Logging + +### `LogVerbose(verbose bool, message string)` + +Writes `message` as a `FormatVerboseMessage` to `os.Stderr` when `verbose` is `true`. This is a convenience helper that avoids repetitive `if verbose` guards throughout the codebase. + +```go +console.LogVerbose(cfg.Verbose, "Loaded 12 workflow files") +``` + ## Utility Functions ### `FormatFileSize(size int64) string` @@ -525,6 +720,42 @@ console.FormatFileSize(1500) // "1.5 KB" console.FormatFileSize(2_100_000) // "2.0 MB" ``` +### `FormatNumber(n int) string` + +Formats a large integer as a compact human-readable string using SI suffixes (`k`, `M`, `B`). + +```go +console.FormatNumber(0) // "0" +console.FormatNumber(999) // "999" +console.FormatNumber(1500) // "1.50k" +console.FormatNumber(1_200_000) // "1.20M" +``` + +### `ToRelativePath(path string) string` + +Converts an absolute path to a path relative to the current working directory. If the relative path would require traversing parent directories (`..`), the original absolute path is returned unchanged. + +```go +// When cwd is /home/user/projects: +console.ToRelativePath("/home/user/projects/workflow.md") // "workflow.md" +console.ToRelativePath("/etc/hosts") // "/etc/hosts" +``` + +### `FormatErrorWithSuggestions(message string, suggestions []string) string` + +Formats an error message followed by a bulleted list of actionable suggestions. Returns an empty suggestions block when `suggestions` is nil or empty. + +```go +msg := console.FormatErrorWithSuggestions( + "Unknown engine 'myengine'", + []string{ + "Valid engines are: copilot, claude, codex", + "Check your workflow frontmatter", + }, +) +fmt.Fprint(os.Stderr, msg) +``` + ### `FormatBanner() string` Returns the `gh aw` ASCII art banner as a styled string.