From 88b17193c9d50221298552cacb79d627d63af80c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 17:33:54 +0000 Subject: [PATCH 1/5] Initial plan From ca9862ef90da39caab5c563c6c9c296ead258be2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 17:44:41 +0000 Subject: [PATCH 2/5] cobra improvements: Example fields, AddGroup, improved comments, test fixes Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/ea20cecf-d23b-471c-aa2d-51a42136e45d Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --- internal/cmd/completion.go | 7 ++++- internal/cmd/completion_test.go | 5 ++++ internal/cmd/flags_test.go | 47 +++++++++++++-------------------- internal/cmd/proxy.go | 13 +++++++++ internal/cmd/root.go | 20 +++++++++++--- 5 files changed, 59 insertions(+), 33 deletions(-) diff --git a/internal/cmd/completion.go b/internal/cmd/completion.go index e1506f60..34da2db3 100644 --- a/internal/cmd/completion.go +++ b/internal/cmd/completion.go @@ -46,6 +46,7 @@ PowerShell: PS> awmg completion powershell > awmg.ps1 # and source this file from your PowerShell profile. `, + GroupID: "utils", DisableFlagsInUseLine: true, ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), @@ -67,7 +68,11 @@ PowerShell: }, } - // Override the parent's PersistentPreRunE to skip validation for completion command + // Override PersistentPreRunE to skip the root command's validation hook. + // Note: cobra does NOT automatically chain PersistentPreRunE hooks — unlike + // middleware-style frameworks, a child's PersistentPreRunE completely replaces + // the parent's. We explicitly set a no-op here so that completion generation + // runs without requiring a config file. cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { return nil } diff --git a/internal/cmd/completion_test.go b/internal/cmd/completion_test.go index 48067b59..739b18c0 100644 --- a/internal/cmd/completion_test.go +++ b/internal/cmd/completion_test.go @@ -65,6 +65,9 @@ func newTestRootWithCompletion() (*cobra.Command, *cobra.Command) { root := &cobra.Command{ Use: "awmg", } + // Mirror the real root's group definitions so GroupID assignments on + // subcommands are valid when root.Execute() is called in tests. + root.AddGroup(&cobra.Group{ID: "utils", Title: "Utilities:"}) completion := newCompletionCmd() root.AddCommand(completion) return root, completion @@ -283,6 +286,8 @@ func TestNewCompletionCmd_OverridesParentPersistentPreRunE(t *testing.T) { return assert.AnError }, } + // Add the group so the completion command's GroupID is valid. + root.AddGroup(&cobra.Group{ID: "utils", Title: "Utilities:"}) completion := newCompletionCmd() root.AddCommand(completion) diff --git a/internal/cmd/flags_test.go b/internal/cmd/flags_test.go index 2fab28a2..201b2dd8 100644 --- a/internal/cmd/flags_test.go +++ b/internal/cmd/flags_test.go @@ -103,51 +103,40 @@ func TestRegisterFlagCompletions(t *testing.T) { t.Run("config flag completion returns toml extension filter", func(t *testing.T) { cmd := setupCmd(t) - completionFn, ok := cmd.GetFlagCompletionFunc("config") - require.True(t, ok, "config flag should have a completion function registered") - require.NotNil(t, completionFn, "config completion function should not be nil") - - completions, directive := completionFn(cmd, nil, "") - assert.Equal(t, cobra.ShellCompDirectiveFilterFileExt, directive, - "config flag should use FilterFileExt directive for .toml files") - assert.Equal(t, []string{"toml"}, completions, + flag := cmd.Flags().Lookup("config") + require.NotNil(t, flag, "config flag should be registered") + exts, ok := flag.Annotations[cobra.BashCompFilenameExt] + require.True(t, ok, "config flag should have filename extension annotation") + assert.Equal(t, []string{"toml"}, exts, "config flag should complete with .toml extension") }) t.Run("log-dir flag completion returns directory filter", func(t *testing.T) { cmd := setupCmd(t) - completionFn, ok := cmd.GetFlagCompletionFunc("log-dir") - require.True(t, ok, "log-dir flag should have a completion function registered") - - completions, directive := completionFn(cmd, nil, "") - assert.Equal(t, cobra.ShellCompDirectiveFilterDirs, directive, - "log-dir flag should use FilterDirs directive") - assert.Nil(t, completions, "log-dir flag completion should return nil completions") + flag := cmd.Flags().Lookup("log-dir") + require.NotNil(t, flag, "log-dir flag should be registered") + _, ok := flag.Annotations[cobra.BashCompSubdirsInDir] + assert.True(t, ok, "log-dir flag should have directory annotation") }) t.Run("payload-dir flag completion returns directory filter", func(t *testing.T) { cmd := setupCmd(t) - completionFn, ok := cmd.GetFlagCompletionFunc("payload-dir") - require.True(t, ok, "payload-dir flag should have a completion function registered") - - completions, directive := completionFn(cmd, nil, "") - assert.Equal(t, cobra.ShellCompDirectiveFilterDirs, directive, - "payload-dir flag should use FilterDirs directive") - assert.Nil(t, completions, "payload-dir flag completion should return nil completions") + flag := cmd.Flags().Lookup("payload-dir") + require.NotNil(t, flag, "payload-dir flag should be registered") + _, ok := flag.Annotations[cobra.BashCompSubdirsInDir] + assert.True(t, ok, "payload-dir flag should have directory annotation") }) t.Run("env flag completion returns .env extension filter", func(t *testing.T) { cmd := setupCmd(t) - completionFn, ok := cmd.GetFlagCompletionFunc("env") - require.True(t, ok, "env flag should have a completion function registered") - - completions, directive := completionFn(cmd, nil, "") - assert.Equal(t, cobra.ShellCompDirectiveFilterFileExt, directive, - "env flag should use FilterFileExt directive for .env files") - assert.Equal(t, []string{"env"}, completions, + flag := cmd.Flags().Lookup("env") + require.NotNil(t, flag, "env flag should be registered") + exts, ok := flag.Annotations[cobra.BashCompFilenameExt] + require.True(t, ok, "env flag should have filename extension annotation") + assert.Equal(t, []string{"env"}, exts, "env flag should complete with .env extension") }) diff --git a/internal/cmd/proxy.go b/internal/cmd/proxy.go index 72782765..82b5128b 100644 --- a/internal/cmd/proxy.go +++ b/internal/cmd/proxy.go @@ -97,6 +97,15 @@ Local usage: --guard-wasm guards/github-guard/github_guard.wasm \ --policy '{"allow-only":{"repos":["org/repo"],"min-integrity":"approved"}}' \ --listen localhost:8443 --tls`, + Example: ` # Run with auto-detected baked-in guard (container image) + awmg proxy --policy '{"allow-only":{"repos":["org/repo"],"min-integrity":"approved"}}' + + # Run locally with explicit guard WASM and TLS + awmg proxy \ + --guard-wasm guards/github_guard.wasm \ + --policy '{"allow-only":{"repos":["org/repo"]}}' \ + --listen localhost:8443 --tls`, + GroupID: "modes", SilenceUsage: true, RunE: runProxy, } @@ -107,6 +116,10 @@ Local usage: } else { guardHelp += " (required)" } + // Note: --listen and --log-dir are re-declared here (not inherited from rootCmd as + // persistent flags) because the proxy subcommand has different defaults and a distinct + // purpose: it runs as a standalone HTTPS forward proxy, not an MCP gateway. Keeping + // them independent avoids confusion and allows each command to evolve separately. cmd.Flags().StringVar(&proxyGuardWasm, "guard-wasm", defaultGuard, guardHelp) cmd.Flags().StringVar(&proxyPolicy, "policy", os.Getenv("MCP_GATEWAY_GUARD_POLICY_JSON"), "Guard policy JSON") cmd.Flags().StringVar(&proxyToken, "github-token", "", "Fallback GitHub API token (default: forwards client Authorization header)") diff --git a/internal/cmd/root.go b/internal/cmd/root.go index f0d60c6f..0466d132 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -46,11 +46,19 @@ var ( ) var rootCmd = &cobra.Command{ - Use: "awmg", - Short: "MCPG MCP proxy server", - Version: cliVersion, + Use: "awmg", + Short: "MCPG MCP proxy server", Long: `MCPG is a proxy server for Model Context Protocol (MCP) servers. It provides routing, aggregation, and management of multiple MCP backend servers.`, + Example: ` # Start in routed mode with a config file + awmg --config config.toml --routed + + # Start in unified mode reading config from stdin + cat config.json | awmg --config-stdin --unified --listen 0.0.0.0:3000 + + # Run with debug logging + DEBUG=* awmg --config config.toml`, + Version: cliVersion, Args: cobra.NoArgs, SilenceUsage: true, // Don't show help on runtime errors SilenceErrors: true, // Prevent cobra from printing errors — Execute() caller handles display @@ -73,6 +81,12 @@ func init() { // Register custom flag completions registerFlagCompletions(rootCmd) + // Group subcommands for organized help output + rootCmd.AddGroup( + &cobra.Group{ID: "modes", Title: "Operation Modes:"}, + &cobra.Group{ID: "utils", Title: "Utilities:"}, + ) + // Add completion command rootCmd.AddCommand(newCompletionCmd()) } From 2158e494def6f535bffb6e45e01560ef7e74e521 Mon Sep 17 00:00:00 2001 From: Landon Cox Date: Thu, 23 Apr 2026 15:17:44 -0700 Subject: [PATCH 3/5] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- internal/cmd/proxy.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/cmd/proxy.go b/internal/cmd/proxy.go index 82b5128b..e6afb470 100644 --- a/internal/cmd/proxy.go +++ b/internal/cmd/proxy.go @@ -105,7 +105,6 @@ Local usage: --guard-wasm guards/github_guard.wasm \ --policy '{"allow-only":{"repos":["org/repo"]}}' \ --listen localhost:8443 --tls`, - GroupID: "modes", SilenceUsage: true, RunE: runProxy, } From c3fb85c9e537e00bd467be687c63ec46e14efe57 Mon Sep 17 00:00:00 2001 From: Landon Cox Date: Thu, 23 Apr 2026 15:18:18 -0700 Subject: [PATCH 4/5] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- internal/cmd/proxy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/cmd/proxy.go b/internal/cmd/proxy.go index e6afb470..5a4d09fc 100644 --- a/internal/cmd/proxy.go +++ b/internal/cmd/proxy.go @@ -102,7 +102,7 @@ Local usage: # Run locally with explicit guard WASM and TLS awmg proxy \ - --guard-wasm guards/github_guard.wasm \ + --guard-wasm guards/github-guard/github_guard.wasm \ --policy '{"allow-only":{"repos":["org/repo"]}}' \ --listen localhost:8443 --tls`, SilenceUsage: true, From 10e0a3dfdc287bc401284e0710bca2d5945ff963 Mon Sep 17 00:00:00 2001 From: Landon Cox Date: Thu, 23 Apr 2026 15:18:34 -0700 Subject: [PATCH 5/5] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- internal/cmd/completion_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/cmd/completion_test.go b/internal/cmd/completion_test.go index 739b18c0..9535ff1a 100644 --- a/internal/cmd/completion_test.go +++ b/internal/cmd/completion_test.go @@ -65,8 +65,8 @@ func newTestRootWithCompletion() (*cobra.Command, *cobra.Command) { root := &cobra.Command{ Use: "awmg", } - // Mirror the real root's group definitions so GroupID assignments on - // subcommands are valid when root.Execute() is called in tests. + // Add the real root's "utils" group so GroupID assignments on attached + // subcommands remain valid when root.Execute() is called in tests. root.AddGroup(&cobra.Group{ID: "utils", Title: "Utilities:"}) completion := newCompletionCmd() root.AddCommand(completion)