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
5 changes: 2 additions & 3 deletions cmd/root/feedback.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import (

"github.com/spf13/cobra"

"github.com/docker/cagent/pkg/feedback"
"github.com/docker/cagent/pkg/telemetry"
)

var FeedbackLink = "https://docker.qualtrics.com/jfe/form/SV_cNsCIg92nQemlfw"

// NewFeedbackCmd creates a new feedback command
func NewFeedbackCmd() *cobra.Command {
return &cobra.Command{
Expand All @@ -19,7 +18,7 @@ func NewFeedbackCmd() *cobra.Command {
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
telemetry.TrackCommand("feedback", args)
fmt.Println("Feel free to give feedback:\n", FeedbackLink)
fmt.Println("Feel free to give feedback:\n", feedback.FeedbackLink)
},
}
}
5 changes: 3 additions & 2 deletions cmd/root/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/spf13/cobra"

"github.com/docker/cagent/pkg/environment"
"github.com/docker/cagent/pkg/feedback"
"github.com/docker/cagent/pkg/paths"
"github.com/docker/cagent/pkg/telemetry"
"github.com/docker/cagent/pkg/version"
Expand Down Expand Up @@ -84,7 +85,7 @@ func NewRootCmd() *cobra.Command {
})))
}
if cmd.DisplayName() != "exec" && os.Getenv("CAGENT_HIDE_FEEDBACK_LINK") != "1" {
_, _ = cmd.OutOrStdout().Write([]byte("\nFor any feedback, please visit: " + FeedbackLink + "\n\n"))
_, _ = cmd.OutOrStdout().Write([]byte("\nFor any feedback, please visit: " + feedback.FeedbackLink + "\n\n"))
}

telemetry.SetGlobalTelemetryDebugMode(debugMode)
Expand Down Expand Up @@ -146,7 +147,7 @@ For any feedback, please visit: %s
We collect anonymous usage data to help improve cagent. To disable:
- Set environment variable: TELEMETRY_ENABLED=false

`, FeedbackLink)
`, feedback.FeedbackLink)
_, _ = os.Stderr.WriteString(startupMsg)
}

Expand Down
34 changes: 34 additions & 0 deletions pkg/browser/browser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package browser

import (
"context"
"fmt"
"os/exec"
"runtime"
)

func Open(ctx context.Context, urlToOpen string) error {
var cmd string
var args []string

switch runtime.GOOS {
case "windows":
cmd = "rundll32"
args = []string{"url.dll,FileProtocolHandler", urlToOpen}
case "darwin":
cmd = "open"
args = []string{urlToOpen}
case "linux":
cmd = "xdg-open"
args = []string{urlToOpen}
default:
return fmt.Errorf("unsupported platform: %s", runtime.GOOS)
}

err := exec.CommandContext(ctx, cmd, args...).Start()
if err != nil {
return fmt.Errorf("failed to open browser: %w", err)
}

return nil
}
3 changes: 3 additions & 0 deletions pkg/feedback/feedback.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package feedback

var FeedbackLink = "https://docker.qualtrics.com/jfe/form/SV_cNsCIg92nQemlfw"
32 changes: 3 additions & 29 deletions pkg/tools/mcp/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import (
"log/slog"
"net/http"
"net/url"
"os/exec"
"regexp"
"runtime"
"strings"
"time"

"golang.org/x/oauth2"

"github.com/docker/cagent/pkg/browser"
)

// resourceMetadataFromWWWAuth extracts resource metadata URL from WWW-Authenticate header
Expand Down Expand Up @@ -221,7 +221,7 @@ func exchangeCodeForToken(ctx context.Context, tokenEndpoint, code, codeVerifier

// requestAuthorizationCode requests the user to open the authorization URL and waits for the callback
func requestAuthorizationCode(ctx context.Context, authURL string, callbackServer *CallbackServer, expectedState string) (string, string, error) {
if err := openBrowser(ctx, authURL); err != nil {
if err := browser.Open(ctx, authURL); err != nil {
return "", "", err
}

Expand All @@ -237,32 +237,6 @@ func requestAuthorizationCode(ctx context.Context, authURL string, callbackServe
return code, state, nil
}

func openBrowser(ctx context.Context, urlToOpen string) error {
var cmd string
var args []string

switch runtime.GOOS {
case "windows":
cmd = "rundll32"
args = []string{"url.dll,FileProtocolHandler", urlToOpen}
case "darwin":
cmd = "open"
args = []string{urlToOpen}
case "linux":
cmd = "xdg-open"
args = []string{urlToOpen}
default:
return fmt.Errorf("unsupported platform: %s", runtime.GOOS)
}

err := exec.CommandContext(ctx, cmd, args...).Start()
if err != nil {
return fmt.Errorf("failed to open browser: %w", err)
}

return nil
}

// registerClient performs dynamic client registration
func registerClient(ctx context.Context, authMetadata *authorizationServerMetadata, redirectURI string, scopes []string) (clientID, clientSecret string, err error) {
if authMetadata.RegistrationEndpoint == "" {
Expand Down
32 changes: 32 additions & 0 deletions pkg/tui/commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
tea "github.com/charmbracelet/bubbletea/v2"

"github.com/docker/cagent/pkg/app"
"github.com/docker/cagent/pkg/feedback"
"github.com/docker/cagent/pkg/tui/core"
)

Expand Down Expand Up @@ -38,6 +39,10 @@ type Item struct {
Execute func() tea.Cmd
}

type OpenURLMsg struct {
URL string
}

func BuiltInSessionCommands() []Item {
return []Item{
{
Expand Down Expand Up @@ -83,13 +88,40 @@ func BuiltInSessionCommands() []Item {
}
}

func builtInFeedbackCommands() []Item {
return []Item{
{
ID: "feedback.bug",
Label: "Report Bug",
Description: "Report a bug or issue",
Category: "Feedback",
Execute: func() tea.Cmd {
return core.CmdHandler(OpenURLMsg{URL: "https://github.com/docker/cagent/issues/new/choose"})
},
},
{
ID: "feedback.feeedback",
Label: "Give Feedback",
Description: "Provide feedback about cagent",
Category: "Feedback",
Execute: func() tea.Cmd {
return core.CmdHandler(OpenURLMsg{URL: feedback.FeedbackLink})
},
},
}
}

// BuildCommandCategories builds the list of command categories for the command palette
func BuildCommandCategories(ctx context.Context, application *app.App) []Category {
categories := []Category{
{
Name: "Session",
Commands: BuiltInSessionCommands(),
},
{
Name: "Feedback",
Commands: builtInFeedbackCommands(),
},
}

agentCommands := application.CurrentAgentCommands(ctx)
Expand Down
5 changes: 5 additions & 0 deletions pkg/tui/tui.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/charmbracelet/lipgloss/v2"

"github.com/docker/cagent/pkg/app"
"github.com/docker/cagent/pkg/browser"
"github.com/docker/cagent/pkg/evaluation"
"github.com/docker/cagent/pkg/runtime"
"github.com/docker/cagent/pkg/tui/commands"
Expand Down Expand Up @@ -172,6 +173,10 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
resolvedCommand := a.application.ResolveCommand(context.Background(), msg.Command)
return a, core.CmdHandler(editor.SendMsg{Content: resolvedCommand})

case commands.OpenURLMsg:
_ = browser.Open(context.Background(), msg.URL)
return a, nil

case error:
a.err = msg
return a, nil
Expand Down
Loading