Skip to content

Commit afe047b

Browse files
Copilotpelikhangh-aw-botgithub-actions[bot]
authored
fix(cli): address 16 CLI consistency issues from 2026-07-20 audit (#46854)
* Initial plan * fix(cli): address CLI consistency issues from 2026-07-20 audit - TG-1: Add missing article 'the' before 'workflow_dispatch trigger' in trial help - TG-2: Fix phrasing 'created as private and kept' → 'created as a private repository and retained' in trial help - TG-3: Capitalize 'Markdown' as proper noun in cli.md - TG-4: Fix tense inconsistency in checks command ('are blocking' → 'blocked') - TG-5: Add 'Requires a clean working directory' to --push flag help text - FN-1: Add --delete-host-repo-before flag; keep --force-delete-host-repo-before as deprecated - FN-2: Add --no-remove-orphans flag for remove command; keep --keep-orphans as deprecated - FN-3: Remove uppercase -F shorthand from --raw-field; update example to --raw-field - DM-3: Add [HOST/] prefix to doctor --repo flag description - DM-4: Update root help 'View execution logs' → 'Download and analyze execution logs' - DM-5: Fix 'pinned Actions' → 'pinned actions' in cli.md - DM-6: Fix 'from The Agentics collection' → 'from the Agentics collection' in cli.md - DM-7: Add note about default action-bump behavior to update command Long description - ID-1: Standardize --evals flag to positive phrasing in audit command - ID-2: Expand run --approve description to mention strict-mode behavior - ID-3: Fix new --force description to 'Overwrite existing workflow files without confirmation' - Update all related tests and docs Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> * fix(cli): improve trial command variable naming clarity Rename forceDeleteHostRepo variable to legacyForceDelete for clarity when merging the deprecated --force-delete-host-repo-before and new --delete-host-repo-before flags, making the intent more explicit. Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> * fix(cli): address PR review follow-up Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com> * test(cli): clarify Windows cleanup retry loop Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com> * test(cli): name Windows cleanup retry settings Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 8b820ae commit afe047b

15 files changed

Lines changed: 80 additions & 53 deletions

.github/aw/cli-commands.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ gh aw run <workflow-name> # Run by short name
7373
gh aw run <workflow-name>.md # Alternative: explicit .md extension
7474
gh aw run <workflow-name> --ref main # Run on a specific branch/tag/SHA
7575
gh aw run <workflow-name> --repeat 3 # Run 4 times total (1 + 3 repeats)
76-
gh aw run <workflow-name> -F key=value # Pass a specific input (alias: --raw-field)
76+
gh aw run <workflow-name> --raw-field key=value # Pass a specific input
7777
```
7878
7979
**MCP equivalent**: Not available. Fallback: use the GitHub MCP server's `create_workflow_dispatch` with `workflow_id: <workflow-name>.lock.yml`.

cmd/gh-aw/main.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ Common Tasks:
9292
` + string(constants.CLIExtensionPrefix) + ` compile # Compile all workflows
9393
` + string(constants.CLIExtensionPrefix) + ` run my-workflow # Execute a workflow
9494
` + string(constants.CLIExtensionPrefix) + ` status # Check workflow status
95-
` + string(constants.CLIExtensionPrefix) + ` logs my-workflow # View execution logs
95+
` + string(constants.CLIExtensionPrefix) + ` logs my-workflow # Download and analyze execution logs
9696
` + string(constants.CLIExtensionPrefix) + ` audit <run-id-or-url> # Audit and compare workflow runs
9797
9898
For detailed help on any command, use:
@@ -173,17 +173,19 @@ The workflow-id is the basename of the Markdown file without the .md extension.
173173
You can provide a substring to match multiple workflows, or a specific workflow-id.
174174
175175
By default, this command also removes orphaned include files that are no longer referenced
176-
by any workflow. Use --keep-orphans to skip this cleanup.`,
177-
Example: ` ` + string(constants.CLIExtensionPrefix) + ` remove my-workflow # Remove specific workflow
178-
` + string(constants.CLIExtensionPrefix) + ` remove test- # Remove all workflows containing 'test-' in name
179-
` + string(constants.CLIExtensionPrefix) + ` remove old- --keep-orphans # Remove workflows but keep orphaned includes
176+
by any workflow. Use --no-remove-orphans to skip this cleanup.`,
177+
Example: ` ` + string(constants.CLIExtensionPrefix) + ` remove my-workflow # Remove specific workflow
178+
` + string(constants.CLIExtensionPrefix) + ` remove test- # Remove all workflows containing 'test-' in name
179+
` + string(constants.CLIExtensionPrefix) + ` remove old- --no-remove-orphans # Remove workflows but keep orphaned includes
180180
` + string(constants.CLIExtensionPrefix) + ` remove my-workflow --dir .github/workflows/shared # Remove from custom directory`,
181181
RunE: func(cmd *cobra.Command, args []string) error {
182182
var pattern string
183183
if len(args) > 0 {
184184
pattern = args[0]
185185
}
186186
keepOrphans, _ := cmd.Flags().GetBool("keep-orphans")
187+
noRemoveOrphans, _ := cmd.Flags().GetBool("no-remove-orphans")
188+
keepOrphans = keepOrphans || noRemoveOrphans
187189
workflowDir, _ := cmd.Flags().GetString("dir")
188190
return cli.RemoveWorkflows(pattern, keepOrphans, workflowDir)
189191
},
@@ -432,7 +434,7 @@ This command only works with workflows that have workflow_dispatch triggers.
432434
` + string(constants.CLIExtensionPrefix) + ` run daily-perf-improver --repeat 3 # Run 4 times total (1 initial + 3 repeats)
433435
` + string(constants.CLIExtensionPrefix) + ` run daily-perf-improver --enable-if-needed # Enable if disabled, run, then restore state
434436
` + string(constants.CLIExtensionPrefix) + ` run daily-perf-improver --auto-merge-prs # Auto-merge any PRs created during execution
435-
` + string(constants.CLIExtensionPrefix) + ` run daily-perf-improver -F name=value -F env=prod # Pass workflow inputs
437+
` + string(constants.CLIExtensionPrefix) + ` run daily-perf-improver --raw-field name=value --raw-field env=prod # Pass workflow inputs
436438
` + string(constants.CLIExtensionPrefix) + ` run daily-perf-improver --push # Commit, push, and dispatch the workflow
437439
` + string(constants.CLIExtensionPrefix) + ` run daily-perf-improver --dry-run # Preview without triggering workflow runs
438440
` + string(constants.CLIExtensionPrefix) + ` run daily-perf-improver --json # Output results in JSON format`,
@@ -711,7 +713,7 @@ Use "` + string(constants.CLIExtensionPrefix) + ` help all" to show help for all
711713
cli.RegisterEngineFlagCompletion(initCmd)
712714

713715
// Add flags to new command
714-
newCmd.Flags().BoolP("force", "f", false, "Overwrite existing files without confirmation")
716+
newCmd.Flags().BoolP("force", "f", false, "Overwrite existing workflow files without confirmation")
715717
newCmd.Flags().BoolP("interactive", "i", false, "Launch interactive workflow creation wizard")
716718
newCmd.Flags().StringP("engine", "e", "", cli.EngineFlagOverrideUsage)
717719
cli.RegisterEngineFlagCompletion(newCmd)
@@ -774,7 +776,9 @@ Use "` + string(constants.CLIExtensionPrefix) + ` help all" to show help for all
774776
rootCmd.AddCommand(compileCmd)
775777

776778
// Add flags to remove command
779+
removeCmd.Flags().Bool("no-remove-orphans", false, "Skip removal of orphaned include files that are no longer referenced by any workflow")
777780
removeCmd.Flags().Bool("keep-orphans", false, "Skip removal of orphaned include files that are no longer referenced by any workflow")
781+
_ = removeCmd.Flags().MarkDeprecated("keep-orphans", "use --no-remove-orphans instead")
778782
removeCmd.Flags().StringP("dir", "d", "", "Workflow directory (default: $GH_AW_WORKFLOWS_DIR or .github/workflows)")
779783
// Register completions for remove command
780784
removeCmd.ValidArgsFunction = cli.CompleteWorkflowNames
@@ -795,10 +799,11 @@ Use "` + string(constants.CLIExtensionPrefix) + ` help all" to show help for all
795799
runCmd.Flags().String("ref", "", "Branch or tag name to run the workflow on (default: current branch)")
796800
runCmd.Flags().Bool("auto-merge-prs", false, "Auto-merge any pull requests created during the workflow execution")
797801
runCmd.Flags().StringArrayP("raw-field", "F", []string{}, "Pass a workflow dispatch input in key=value format (can be specified multiple times)")
798-
runCmd.Flags().Bool("push", false, "Commit and push workflow files (including transitive imports) before running")
802+
_ = runCmd.Flags().MarkShorthandDeprecated("raw-field", "use --raw-field instead")
803+
runCmd.Flags().Bool("push", false, "Commit and push workflow files (including transitive imports) before running. Refuses to proceed when unrelated files are already staged.")
799804
runCmd.Flags().Bool("dry-run", false, "Preview workflow execution without triggering runs on GitHub Actions")
800805
runCmd.Flags().BoolP("json", "j", false, "Output results in JSON format")
801-
runCmd.Flags().Bool("approve", false, "Approve safe update manifest changes when --push triggers an automatic recompile step")
806+
runCmd.Flags().Bool("approve", false, "Approve safe update manifest changes when --push triggers an automatic recompile step. When strict mode is active (the default), the recompile step enforces safe update checking; pass this flag to approve those changes.")
802807
// Register completions for run command
803808
runCmd.ValidArgsFunction = cli.CompleteWorkflowNames
804809
cli.RegisterEngineFlagCompletion(runCmd)

cmd/gh-aw/main_help_text_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,18 @@ func TestRunCommandHelpTextConsistency(t *testing.T) {
1313
assert.Contains(t, runCmd.Long, "this command enters interactive mode and shows", "run command interactive mode text should be explicit")
1414

1515
runApprove := runCmd.Flags().Lookup("approve")
16+
runPush := runCmd.Flags().Lookup("push")
17+
runRawField := runCmd.Flags().Lookup("raw-field")
1618
compileApprove := compileCmd.Flags().Lookup("approve")
1719
require.NotNil(t, runApprove, "run command should define --approve")
20+
require.NotNil(t, runPush, "run command should define --push")
21+
require.NotNil(t, runRawField, "run command should define --raw-field")
1822
require.NotNil(t, compileApprove, "compile command should define --approve")
1923
assert.Contains(t, compileApprove.Usage, "safe update changes", "compile --approve should describe compiler safe update approval")
20-
assert.Equal(t, "Approve safe update manifest changes when --push triggers an automatic recompile step", runApprove.Usage, "run --approve should explain the --push-triggered recompile behavior")
24+
assert.Equal(t, "Approve safe update manifest changes when --push triggers an automatic recompile step. When strict mode is active (the default), the recompile step enforces safe update checking; pass this flag to approve those changes.", runApprove.Usage, "run --approve should explain the --push-triggered recompile behavior with strict mode context")
25+
assert.Equal(t, "Commit and push workflow files (including transitive imports) before running. Refuses to proceed when unrelated files are already staged.", runPush.Usage, "run --push should describe the staged-files precondition precisely")
26+
assert.Equal(t, "F", runRawField.Shorthand, "run --raw-field should keep the legacy -F shorthand for compatibility")
27+
assert.Equal(t, "use --raw-field instead", runRawField.ShorthandDeprecated, "run -F shorthand should be marked deprecated")
2128
}
2229

2330
func TestCompileScheduleSeedHelpUsesConsistentQuotes(t *testing.T) {

docs/interactive-run-mode.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ All standard `run` command flags work in interactive mode:
5858
The following flags are NOT supported in interactive mode:
5959
- `--repeat` - Use the displayed command for repeated runs
6060
- `--enable-if-needed` - Enable workflows manually first
61-
- `-F` / `--raw-field` - Inputs are collected interactively
61+
- `--raw-field` - Inputs are collected interactively
6262

6363
## CI Detection
6464

docs/src/content/docs/experimental/trial-ops.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ gh aw trial githubnext/agentics/my-workflow \
9494

9595
```bash
9696
gh aw trial ./my-workflow.md --delete-host-repo-after # Delete after completion
97-
gh aw trial ./my-workflow.md --force-delete-host-repo-before # Clean slate before running
97+
gh aw trial ./my-workflow.md --delete-host-repo-before # Clean slate before running
9898
```
9999

100100
## Understanding Trial Results

docs/src/content/docs/setup/cli.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ sidebar:
55
order: 200
66
---
77

8-
The `gh aw` CLI extension enables developers to create, manage, and execute AI-powered workflows directly from the command line. It transforms natural language markdown files into GitHub Actions.
8+
The `gh aw` CLI extension enables developers to create, manage, and execute AI-powered workflows directly from the command line. It transforms natural language Markdown files into GitHub Actions.
99

1010
## Most Common Commands
1111

@@ -133,7 +133,7 @@ Use `gh aw version` to print the current version.
133133

134134
### The `--push` Flag
135135

136-
`gh aw run --push` stages all changes, commits them, and pushes before dispatching the workflow. It requires a clean working directory.
136+
`gh aw run --push` stages workflow files (including transitive imports), commits them, and pushes before dispatching the workflow. It refuses to proceed when unrelated files are already staged.
137137

138138
For `init`, `update`, and `upgrade`, use `--create-pull-request` instead.
139139

@@ -178,7 +178,7 @@ When the Copilot engine is selected, the wizard prompts the user to choose an au
178178

179179
#### `add`
180180

181-
Add workflows from The Agentics collection or other repositories to `.github/workflows`. For remote workflows, this command follows frontmatter [`redirect`](/gh-aw/reference/frontmatter/#redirect-redirect) declarations before installation.
181+
Add workflows from the Agentics collection or other repositories to `.github/workflows`. For remote workflows, this command follows frontmatter [`redirect`](/gh-aw/reference/frontmatter/#redirect-redirect) declarations before installation.
182182

183183
```bash wrap
184184
gh aw add githubnext/agentics/ci-doctor # Add single workflow
@@ -341,7 +341,7 @@ Unlike `gh aw upgrade`, `gh aw compile` does not run codemods unless you pass `-
341341

342342
**Dependabot Integration (`--dependabot`):** Generates dependency manifests and `.github/dependabot.yml` by analyzing runtime tools across all workflows. See [Dependabot Support reference](/gh-aw/reference/dependabot/).
343343

344-
**Strict Mode (`--strict`):** Enforces security best practices: no write permissions (use [safe-outputs](/gh-aw/reference/safe-outputs/)), explicit `network` config, no wildcard domains, pinned Actions, no deprecated fields. See [Strict Mode reference](/gh-aw/reference/frontmatter/#strict-mode-strict).
344+
**Strict Mode (`--strict`):** Enforces security best practices: no write permissions (use [safe-outputs](/gh-aw/reference/safe-outputs/)), explicit `network` config, no wildcard domains, pinned actions, no deprecated fields. See [Strict Mode reference](/gh-aw/reference/frontmatter/#strict-mode-strict).
345345

346346
**Shared Workflows:** Workflows without an `on` field are detected as shared components. Validated with relaxed schema and skip compilation. See [Imports reference](/gh-aw/reference/imports/).
347347

@@ -392,7 +392,7 @@ gh aw trial ./workflow.md --host-repo owner/repo # Run directly in repository
392392
gh aw trial ./workflow.md --dry-run # Preview without executing
393393
```
394394

395-
**Options:** `-e/--engine`, `--repeat`, `--delete-host-repo-after`, `--logical-repo/-l`, `--clone-repo`, `--trigger-context`, `--host-repo`, `--dry-run`, `--append`, `--auto-merge-prs`, `--no-security-scanner`, `--force-delete-host-repo-before`, `--json/-j`, `--timeout`, `--yes/-y`
395+
**Options:** `-e/--engine`, `--repeat`, `--delete-host-repo-after`, `--logical-repo/-l`, `--clone-repo`, `--trigger-context`, `--host-repo`, `--dry-run`, `--append`, `--auto-merge-prs`, `--no-security-scanner`, `--delete-host-repo-before`, `--json/-j`, `--timeout`, `--yes/-y`
396396

397397
**Secret Handling:** API keys required for the selected engine are automatically checked. If missing from the target repository, they are prompted for interactively and uploaded.
398398

@@ -410,7 +410,7 @@ gh aw run workflow --dry-run # Preview without triggering workflo
410410
gh aw run workflow --json # Output triggered workflow results as JSON
411411
```
412412

413-
**Options:** `--repeat`, `--push` (see [--push flag](#the---push-flag)), `--ref`, `--enable-if-needed`, `--json/-j`, `--auto-merge-prs`, `--dry-run`, `--engine/-e`, `--raw-field/-F`, `--repo/-r`, `--approve`
413+
**Options:** `--repeat`, `--push` (see [--push flag](#the---push-flag)), `--ref`, `--enable-if-needed`, `--json/-j`, `--auto-merge-prs`, `--dry-run`, `--engine/-e`, `--raw-field`, `--repo/-r`, `--approve`
414414

415415
When `--json` is set, a JSON array of triggered workflow results is written to stdout.
416416

@@ -698,12 +698,12 @@ gh aw disable ci-doctor --repo owner/repo # Disable in specific repository
698698
Remove workflows (both `.md` and `.lock.yml`). Accepts a workflow ID (basename without `.md`) or a substring pattern matching multiple workflows. By default, also removes orphaned include files no longer referenced by any workflow.
699699

700700
```bash wrap
701-
gh aw remove my-workflow # Remove specific workflow
702-
gh aw remove test- # Remove all workflows containing 'test-' in their name
703-
gh aw remove my-workflow --keep-orphans # Remove but keep orphaned include files
701+
gh aw remove my-workflow # Remove specific workflow
702+
gh aw remove test- # Remove all workflows containing 'test-' in their name
703+
gh aw remove my-workflow --no-remove-orphans # Remove but keep orphaned include files
704704
```
705705

706-
**Options:** `--dir/-d`, `--keep-orphans`
706+
**Options:** `--dir/-d`, `--no-remove-orphans`
707707

708708
#### `update`
709709

pkg/cli/audit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func registerAuditCommandFlags(cmd *cobra.Command) {
111111
cmd.Flags().Bool("stdin", false, "Read workflow run IDs or URLs from stdin (one per line) instead of positional arguments")
112112
cmd.Flags().String("experiment", "", "Filter to runs that include this experiment name")
113113
cmd.Flags().String("variant", "", "Filter to runs with a specific variant value (requires --experiment)")
114-
cmd.Flags().Bool("evals", false, "Skip runs that do not contain evals results (evals.jsonl); automatically downloads the usage artifact (which includes evals) when --artifacts is narrowed")
114+
cmd.Flags().Bool("evals", false, "Filter to runs containing evals results (evals.jsonl); automatically downloads the usage artifact (which includes evals) when --artifacts is narrowed")
115115
RegisterDirFlagCompletion(cmd, "output")
116116
}
117117

pkg/cli/checks_command.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const (
2828
CheckStatePending CheckState = "pending"
2929
// CheckStateNoChecks indicates no checks have been configured or triggered.
3030
CheckStateNoChecks CheckState = "no_checks"
31-
// CheckStatePolicyBlocked indicates policy or account gates are blocking the PR.
31+
// CheckStatePolicyBlocked indicates policy or account gates blocked the PR.
3232
CheckStatePolicyBlocked CheckState = "policy_blocked"
3333
// CheckStateSuccess indicates all checks passed.
3434
CheckStateSuccess CheckState = "success"
@@ -85,7 +85,7 @@ Maps PR check rollups to one of the following normalized states:
8585
failed - one or more checks failed
8686
pending - checks are still running or queued
8787
no_checks - no checks configured or triggered
88-
policy_blocked - policy or account gates are blocking the PR
88+
policy_blocked - policy or account gates blocked the PR
8989
9090
` + "Raw check run and commit status signals are included in JSON output." + `
9191

pkg/cli/compile_integration_test.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ var (
2424
binaryTempDir string
2525
)
2626

27+
const (
28+
windowsRemoveRetries = 10
29+
windowsRemoveRetryDelay = 100 * time.Millisecond
30+
)
31+
2732
// TestMain builds the gh-aw binary once before running tests
2833
func TestMain(m *testing.M) {
2934
// Get project root
@@ -150,7 +155,7 @@ func setupIntegrationTest(t *testing.T) *integrationTestSetup {
150155
if err != nil {
151156
t.Fatalf("Failed to change back to original working directory: %v", err)
152157
}
153-
err = os.RemoveAll(tempDir)
158+
err = removeAllWithRetry(tempDir)
154159
if err != nil {
155160
t.Fatalf("Failed to remove temp directory: %v", err)
156161
}
@@ -229,6 +234,27 @@ Please check the repository for any open issues and create a summary.
229234
t.Logf("Successfully compiled workflow to %s", lockFilePath)
230235
}
231236

237+
func removeAllWithRetry(path string) error {
238+
attempts := 1
239+
if runtime.GOOS == "windows" {
240+
attempts = windowsRemoveRetries
241+
}
242+
243+
var err error
244+
for i := 0; i < attempts; i++ {
245+
err = os.RemoveAll(path)
246+
if err == nil || os.IsNotExist(err) {
247+
return nil
248+
}
249+
if runtime.GOOS != "windows" {
250+
return err
251+
}
252+
time.Sleep(windowsRemoveRetryDelay)
253+
}
254+
255+
return err
256+
}
257+
232258
func TestCompileWithIncludeWithEmptyFrontmatterUnderPty(t *testing.T) {
233259
if runtime.GOOS == "windows" {
234260
t.Skip("PTY-based test is not supported on Windows")

pkg/cli/doctor_command.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ target the correct host.`,
5959
},
6060
}
6161

62-
cmd.Flags().StringP("repo", "r", "", "Target repository in owner/repo format")
62+
cmd.Flags().StringP("repo", "r", "", "Target repository in [HOST/]owner/repo format")
6363
cmd.Flags().StringP("dir", "d", "", "Checkout directory to inspect (defaults to the repo name)")
6464
cmd.Flags().String("require-owner-type", "any", "Require a specific owner type: any, org, or user")
6565
addJSONFlag(cmd)

0 commit comments

Comments
 (0)