Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions pkg/console/console.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func FormatSuccessMessage(message string) string {

// FormatInfoMessage formats an informational message
func FormatInfoMessage(message string) string {
return applyStyle(styles.Info, "β„Ή ") + message
return applyStyle(styles.Info, "i ") + message

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/zoom-out] i (U+2139) is already a BMP character β€” yet the PR description explicitly lists it as an "already-lightweight" unchanged symbol while this line changes it to plain i.

Replacing a visually distinct, well-supported BMP glyph with the letter i weakens visual differentiation without addressing the stated compatibility goal (supplementary-plane emoji). Consider reverting this change, or update the PR description to accurately reflect that 8 symbols are swapped, not 6.

πŸ’‘ PR description contradiction

The PR description states:

Already-lightweight BMP symbols (βœ“, βœ—, ⚠, ⚑, i, β€’) are unchanged.

But i (U+2139) IS changed here, and ⚑ (U+26A1) is also changed in FormatCommandMessage. Neither is a supplementary-plane character. Updating the description table to include these two swaps would make the scope accurate.

}
Comment on lines 151 to 154

// FormatWarningMessage formats a warning message
Expand Down Expand Up @@ -223,22 +223,22 @@ func RenderTable(config TableConfig) string {

// FormatCommandMessage formats a command execution message
func FormatCommandMessage(command string) string {
return applyStyle(styles.Command, "⚑ ") + command
return applyStyle(styles.Command, "$ ") + command

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/zoom-out] $ collides with the universal shell-prompt convention. Output like $ gh aw compile workflow.md reads as a shell prompt inviting user input rather than a progress indicator, and it clashes directly with every piece of documentation that shows commands prefixed with $ to mean "type this in your terminal".

⚑ (U+26A1) β€” already a BMP character β€” could be kept here since the stated goal is replacing supplementary-plane emoji only. Alternatively, β–Ά (U+25B6) or > would be unambiguous execution indicators.

πŸ’‘ Convention conflict example

In gh-aw docs, shell examples look like:

$ gh aw compile workflow.md

If FormatCommandMessage also emits $ gh aw compile workflow.md, the two usages become visually indistinguishable, which is confusing in log output or step summaries.

}
Comment on lines 224 to 227

// FormatProgressMessage formats a progress/activity message
func FormatProgressMessage(message string) string {
return applyStyle(styles.Progress, "πŸ”¨ ") + message
return applyStyle(styles.Progress, "β–Έ ") + message
}

// FormatPromptMessage formats a user prompt message
func FormatPromptMessage(message string) string {
return applyStyle(styles.Prompt, "❓ ") + message
return applyStyle(styles.Prompt, "? ") + message
}

// FormatVerboseMessage formats verbose debugging output
func FormatVerboseMessage(message string) string {
return applyStyle(styles.Verbose, "πŸ” ") + message
return applyStyle(styles.Verbose, "Β» ") + message
}

// FormatListItem formats an item in a list
Expand Down
24 changes: 12 additions & 12 deletions pkg/console/console_formatting_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ func TestFormatCommandMessage(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
result := FormatCommandMessage(tt.command)

// Should contain the thunderbolt emoji prefix
if !strings.Contains(result, "⚑") {
t.Errorf("FormatCommandMessage() should contain ⚑ prefix")
// Should contain the dollar-sign prefix
if !strings.Contains(result, "$") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Fragile prefix assertion: strings.Contains(result, "$") will pass for any command that itself contains a $ character (e.g., shell variable expansions like gh run --env VAR=$VALUE), so the assertion does not prove the prefix was prepended.

πŸ’‘ Suggested fix

The $ prefix is a poor test anchor because it's valid inside command strings. Prefer asserting position over presence:

// Check the prefix is at the start of the unstyled output:
expected := "$ " + tt.command
if !strings.HasSuffix(result, tt.command) || !strings.Contains(result, "$") {
    // ...
}
// Or better: strip styling and compare the full prefix form:
stripped := stripANSI(result)
if !strings.HasPrefix(stripped, "$ ") {
    t.Errorf("FormatCommandMessage() should start with '$ ' prefix, got: %s", stripped)
}

The chosen replacement symbol $ is one of the most frequent characters in shell commands; the old ⚑ had no such collision risk.

t.Errorf("FormatCommandMessage() should contain $ prefix")
}

// Should contain the command text
Expand Down Expand Up @@ -96,9 +96,9 @@ func TestFormatProgressMessage(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
result := FormatProgressMessage(tt.message)

// Should contain the hammer emoji prefix
if !strings.Contains(result, "πŸ”¨") {
t.Errorf("FormatProgressMessage() should contain πŸ”¨ prefix")
// Should contain the triangle prefix
if !strings.Contains(result, "β–Έ") {
t.Errorf("FormatProgressMessage() should contain β–Έ prefix")
}

// Should contain the message text
Expand Down Expand Up @@ -136,9 +136,9 @@ func TestFormatPromptMessage(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
result := FormatPromptMessage(tt.message)

// Should contain the question mark emoji prefix
if !strings.Contains(result, "❓") {
t.Errorf("FormatPromptMessage() should contain ❓ prefix")
// Should contain the question mark prefix
if !strings.Contains(result, "?") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Vacuous test assertion: strings.Contains(result, "?") can never fail for the "Are you sure you want to continue? [y/N]: " test case because the message already contains ?, so the prefix is never validated.

πŸ’‘ Suggested fix

Assert on a prefix-position check, not a substring anywhere. The simplest fix is to check that the prefix comes before the message, e.g.:

// Instead of:
if !strings.Contains(result, "?")

// Verify the prefix is at the start (strip ANSI codes first if needed):
if !strings.HasPrefix(stripANSI(result), "? ") {
    t.Errorf("FormatPromptMessage() should start with '? ' prefix")
}

As written, the test passes even if FormatPromptMessage strips the prefix entirely β€” the message text itself satisfies the assertion. This makes the test useless for catching regressions in the prefix.

t.Errorf("FormatPromptMessage() should contain ? prefix")
}

// Should contain the message text
Expand Down Expand Up @@ -176,9 +176,9 @@ func TestFormatVerboseMessage(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
result := FormatVerboseMessage(tt.message)

// Should contain the magnifying glass emoji prefix
if !strings.Contains(result, "πŸ”") {
t.Errorf("FormatVerboseMessage() should contain πŸ” prefix")
// Should contain the double-angle prefix
if !strings.Contains(result, "Β»") {
t.Errorf("FormatVerboseMessage() should contain Β» prefix")
}

// Should contain the message text
Expand Down
2 changes: 1 addition & 1 deletion pkg/console/console_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func TestFormatInfoMessage(t *testing.T) {
if !strings.Contains(output, "processing file") {
t.Errorf("Expected output to contain message, got: %s", output)
}
if !strings.Contains(output, "β„Ή") {
if !strings.Contains(output, "i ") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] The test now checks for "i " (letter i + space) rather than a unique character. This is fragile: any message body containing i (e.g. "processing", "file", "writing") would satisfy the assertion even if the prefix were absent.

Consider asserting on the full expected output or anchoring with strings.HasPrefix(output, "i ") to verify the prefix is actually at the start.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Too-broad substring check: strings.Contains(output, "i ") matches any output containing the two-character sequence i β€” which appears naturally in most English sentences β€” so this assertion no longer reliably validates that the info prefix was prepended.

πŸ’‘ Suggested fix

The previous check for "i" worked because that character only appears as an intentional prefix. The new "i " is indistinguishable from message content. Strengthen by verifying position:

// Replace the weak substring check with a prefix check:
stripped := strings.TrimSpace(output)
if !strings.HasPrefix(stripped, "i ") {
    t.Errorf("Expected output to start with info prefix 'i ', got: %s", output)
}

Or update the golden file approach to capture the exact format. The current test would pass even if FormatInfoMessage was changed to a no-op, as long as the message contains "i " somewhere (e.g., "processing input" or "writing item").

t.Errorf("Expected output to contain info icon, got: %s", output)
}
}
Expand Down
14 changes: 7 additions & 7 deletions pkg/console/console_wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,15 @@ func FormatError(err CompilerError) string {
}

func FormatSuccessMessage(message string) string { return "βœ“ " + message }
func FormatInfoMessage(message string) string { return "β„Ή " + message }
func FormatInfoMessage(message string) string { return "i " + message }
func FormatWarningMessage(message string) string { return "⚠ " + message }
Comment on lines 67 to 69
func FormatErrorMessage(message string) string { return "βœ— " + message }
func FormatLocationMessage(message string) string { return "πŸ“ " + message }
func FormatCommandMessage(command string) string { return "⚑ " + command }
func FormatProgressMessage(message string) string { return "πŸ”¨ " + message }
func FormatPromptMessage(message string) string { return "❓ " + message }
func FormatCountMessage(message string) string { return "πŸ“Š " + message }
func FormatVerboseMessage(message string) string { return "πŸ” " + message }
func FormatLocationMessage(message string) string { return "~ " + message }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/zoom-out] ~ conventionally means the home directory in Unix/Linux environments. A location message like ~ Downloaded to: /tmp/logs/workflow-123 will likely be misread as a home-relative path, especially since the actual path is /tmp/... (not under ~).

Consider @, ↓, or β–Έ as unambiguous location/download indicators.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Misleading POSIX shorthand: ~ universally means the current user's home directory in shell/POSIX contexts; using it as a generic location prefix creates a false semantic relationship between the prefix and the displayed path.

πŸ’‘ Suggested fix

Consider a neutral BMP symbol that communicates "location" without implying a home-directory relationship:

// Options that don't carry POSIX home-dir meaning:
func FormatLocationMessage(message string) string { return "@ " + message }  // common location marker
func FormatLocationMessage(message string) string { return "β†’ " + message }  // direction/target
func FormatLocationMessage(message string) string { return "βŒ‚ " + message }  // U+2302, BMP house symbol

A message like ~ Downloaded to: /tmp/logs/workflow-123 reads as if the path is relative to ~ ($HOME), which is wrong for absolute paths and confusing for wasm consumers that have no filesystem home concept.

func FormatCommandMessage(command string) string { return "$ " + command }
func FormatProgressMessage(message string) string { return "β–Έ " + message }
Comment on lines +71 to +73
func FormatPromptMessage(message string) string { return "? " + message }
func FormatCountMessage(message string) string { return "# " + message }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/zoom-out] # is a widely used comment character (shell, Python, YAML, TOML) and a markdown heading marker. A count message like # 42 items processed could be stripped or misinterpreted when output is piped, captured in logs, or rendered as markdown.

Alternatives: Ξ£ (U+03A3), n:, count:, or simply omitting a prefix symbol for count messages.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overloaded symbol: # is simultaneously a shell comment marker, a Markdown heading, a GitHub issue/PR reference prefix, and a programming language comment in many languages β€” none of which convey "count".

πŸ’‘ Suggested fix

If the wasm output is ever consumed by scripts or embedded in Markdown, lines prefixed with # will be silently ignored as comments or rendered as headings. Pick a less overloaded BMP count marker:

// Less overloaded alternatives:
func FormatCountMessage(message string) string { return "n: " + message }  // numeric label
func FormatCountMessage(message string) string { return "Ξ£ " + message }   // U+03A3, BMP summation
func FormatCountMessage(message string) string { return "β€’ " + message }   // neutral bullet (already used for list items β€” keep distinct)

The PR description's own criterion is "semantically equivalent", but # is semantically a comment/heading, not a count.

func FormatVerboseMessage(message string) string { return "Β» " + message }
func FormatListHeader(header string) string { return header }
func FormatListItem(item string) string { return " β€’ " + item }
func FormatSectionHeader(header string) string { return header }
Expand Down
2 changes: 1 addition & 1 deletion pkg/console/terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func ClearLine() {
// Use this at the start of interactive commands (add, trial, init) for a consistent experience.
func ShowWelcomeBanner(description string) {
ClearScreen()
header := "πŸš€ Welcome to GitHub Agentic Workflows!"
header := "β†’ Welcome to GitHub Agentic Workflows!"
if tty.IsStderrTerminal() {
header = styles.Header.Render(header)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
⚑ gh aw compile workflow.md
$ gh aw compile workflow.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
β„Ή Processing workflow file: test.md
i Processing workflow file: test.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
πŸ“ Downloaded to: /tmp/logs/workflow-123
~ Downloaded to: /tmp/logs/workflow-123
Original file line number Diff line number Diff line change
@@ -1 +1 @@
πŸ”¨ Compiling workflow (step 2/5)...
β–Έ Compiling workflow (step 2/5)...
4 changes: 2 additions & 2 deletions pkg/console/verbose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ func TestLogVerbose(t *testing.T) {
if tt.expected {
// Should contain the message
assert.Contains(t, output, tt.message, "Output should contain the message when verbose is enabled")
// Should contain the verbose icon (πŸ”)
assert.Contains(t, output, "πŸ”", "Output should contain verbose formatting")
// Should contain the verbose prefix (Β»)
assert.Contains(t, output, "Β»", "Output should contain verbose formatting")
} else {
// Should be empty
assert.Empty(t, output, "Output should be empty when verbose is disabled")
Expand Down
Loading