From 5aed75d97265e1fb430087836370cee42f1b7f8c Mon Sep 17 00:00:00 2001 From: David Gageot Date: Fri, 6 Mar 2026 19:35:06 +0100 Subject: [PATCH] Fix cobra command and rename more things from cagent to docker agent Signed-off-by: David Gageot --- Taskfile.yml | 3 - cmd/root/a2a.go | 4 +- cmd/root/acp.go | 6 +- cmd/root/alias.go | 26 +-- cmd/root/api.go | 3 +- cmd/root/mcp.go | 8 +- cmd/root/new.go | 8 +- cmd/root/root.go | 267 ++++++++-------------- cmd/root/root_test.go | 107 --------- cmd/root/run.go | 16 +- cmd/root/sandbox.go | 4 +- e2e/binary/binary_test.go | 13 -- e2e/cagent_debug_test.go | 4 +- e2e/cagent_debug_title_test.go | 2 +- e2e/cagent_exec_test.go | 32 +-- e2e/helpers_test.go | 4 +- pkg/a2a/adapter.go | 12 +- pkg/a2a/server.go | 2 +- pkg/acp/agent.go | 10 +- pkg/app/export/html.go | 4 +- pkg/config/config.go | 7 + pkg/config/config_test.go | 34 ++- pkg/config/latest/types.go | 2 +- pkg/connectrpc/server.go | 2 +- pkg/environment/errors.go | 15 +- pkg/environment/sandbox.go | 2 +- pkg/evaluation/eval.go | 6 +- pkg/evaluation/save.go | 2 +- pkg/gateway/catalog.go | 2 +- pkg/mcp/server.go | 2 +- pkg/paths/paths.go | 6 +- pkg/remote/pull.go | 4 +- pkg/runtime/client.go | 4 +- pkg/runtime/connectrpc_client.go | 4 +- pkg/runtime/model_switcher.go | 12 +- pkg/runtime/remote_client.go | 2 +- pkg/session/session.go | 2 +- pkg/session/store.go | 10 +- pkg/session/store_test.go | 6 +- pkg/teamloader/registry.go | 2 +- pkg/telemetry/types.go | 2 +- pkg/toolinstall/registry.go | 2 +- pkg/toolinstall/resolver.go | 2 +- pkg/tools/builtin/fetch_test.go | 12 +- pkg/tools/mcp/mcp.go | 2 +- pkg/tools/mcp/remote.go | 2 +- pkg/tools/mcp/stdio.go | 2 +- pkg/tui/commands/commands.go | 2 +- pkg/tui/components/statusbar/statusbar.go | 4 +- pkg/tui/dialog/theme_picker.go | 2 +- pkg/tui/handlers.go | 8 +- pkg/tui/tui.go | 4 +- pkg/userconfig/userconfig.go | 4 +- 53 files changed, 272 insertions(+), 437 deletions(-) delete mode 100644 cmd/root/root_test.go diff --git a/Taskfile.yml b/Taskfile.yml index 6bc3470a2..742c80e4b 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -1,7 +1,6 @@ version: "3" vars: - DEPRECATED_BINARY_NAME: cagent{{if eq OS "windows"}}.exe{{end}} CLI_PLUGIN_BINARY_NAME: docker-agent{{if eq OS "windows"}}.exe{{end}} MAIN_PKG: ./main.go BUILD_DIR: ./bin @@ -25,7 +24,6 @@ tasks: desc: Build the application binary cmds: - go build -ldflags "{{.LDFLAGS}}" -o {{.BUILD_DIR}}/{{.CLI_PLUGIN_BINARY_NAME}} {{.MAIN_PKG}} - - cp "{{.BUILD_DIR}}/{{.CLI_PLUGIN_BINARY_NAME}}" {{.BUILD_DIR}}/{{.DEPRECATED_BINARY_NAME}} - '{{if ne .CI "true"}}ln -sf {{.USER_WORKING_DIR}}/{{.BUILD_DIR}}/{{.CLI_PLUGIN_BINARY_NAME}} {{.HOME}}/bin/{{.CLI_PLUGIN_BINARY_NAME}}{{end}}' sources: - "{{.GO_SOURCES}}" @@ -36,7 +34,6 @@ tasks: - "go.sum" generates: - "{{.BUILD_DIR}}/{{.CLI_PLUGIN_BINARY_NAME}}" - - "{{.BUILD_DIR}}/{{.DEPRECATED_BINARY_NAME}}" deploy-local: desc: Deploy the docker agent cli-plugin diff --git a/cmd/root/a2a.go b/cmd/root/a2a.go index 198453f9c..041ae59aa 100644 --- a/cmd/root/a2a.go +++ b/cmd/root/a2a.go @@ -22,8 +22,8 @@ func newA2ACmd() *cobra.Command { Use: "a2a |", Short: "Start an agent as an A2A (Agent-to-Agent) server", Long: "Start an A2A server that exposes the agent via the Agent-to-Agent protocol", - Example: ` cagent serve a2a ./agent.yaml - cagent serve a2a agentcatalog/pirate --listen 127.0.0.1:9090`, + Example: ` docker-agent serve a2a ./agent.yaml + docker-agent serve a2a agentcatalog/pirate --listen 127.0.0.1:9090`, Args: cobra.ExactArgs(1), RunE: flags.runA2ACommand, } diff --git a/cmd/root/acp.go b/cmd/root/acp.go index 3a7945626..c76389162 100644 --- a/cmd/root/acp.go +++ b/cmd/root/acp.go @@ -23,9 +23,9 @@ func newACPCmd() *cobra.Command { Use: "acp |", Short: "Start an agent as an ACP (Agent Client Protocol) server", Long: "Start an ACP server that exposes the agent via the Agent Client Protocol", - Example: ` cagent serve acp ./agent.yaml - cagent serve acp ./team.yaml - cagent serve acp agentcatalog/pirate`, + Example: ` docker-agent serve acp ./agent.yaml + docker-agent serve acp ./team.yaml + docker-agent serve acp agentcatalog/pirate`, Args: cobra.ExactArgs(1), RunE: flags.runACPCommand, } diff --git a/cmd/root/alias.go b/cmd/root/alias.go index 4a245a2ad..83c4014ce 100644 --- a/cmd/root/alias.go +++ b/cmd/root/alias.go @@ -22,16 +22,16 @@ func newAliasCmd() *cobra.Command { Short: "Manage aliases", Long: "Create and manage aliases for agent configurations or catalog references.", Example: ` # Create an alias for a catalog agent - cagent alias add code agentcatalog/notion-expert + docker-agent alias add code agentcatalog/notion-expert # Create an alias for a local agent file - cagent alias add myagent ~/myagent.yaml + docker-agent alias add myagent ~/myagent.yaml # List all registered aliases - cagent alias list + docker-agent alias list # Remove an alias - cagent alias remove code`, + docker-agent alias remove code`, GroupID: "advanced", } @@ -63,19 +63,19 @@ the alias is used: --model Override the agent's model (format: [agent=]provider/model) --hide-tool-results Hide tool call results in the TUI`, Example: ` # Create a simple alias - cagent alias add code agentcatalog/notion-expert + docker-agent alias add code agentcatalog/notion-expert # Create an alias that always runs in yolo mode - cagent alias add yolo-coder agentcatalog/coder --yolo + docker-agent alias add yolo-coder agentcatalog/coder --yolo # Create an alias with a specific model - cagent alias add fast-coder agentcatalog/coder --model openai/gpt-4o-mini + docker-agent alias add fast-coder agentcatalog/coder --model openai/gpt-4o-mini # Create an alias with hidden tool results - cagent alias add quiet agentcatalog/coder --hide-tool-results + docker-agent alias add quiet agentcatalog/coder --hide-tool-results # Create an alias with multiple options - cagent alias add turbo agentcatalog/coder --yolo --model anthropic/claude-sonnet-4-0`, + docker-agent alias add turbo agentcatalog/coder --yolo --model anthropic/claude-sonnet-4-0`, Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { return runAliasAddCommand(cmd, args, &flags) @@ -168,9 +168,9 @@ func runAliasAddCommand(cmd *cobra.Command, args []string, flags *aliasAddFlags) } if name == "default" { - out.Printf("\nYou can now run: cagent run %s (or even cagent run)\n", name) + out.Printf("\nYou can now run: docker agent run %s (or even docker agent run)\n", name) } else { - out.Printf("\nYou can now run: cagent run %s\n", name) + out.Printf("\nYou can now run: docker agent run %s\n", name) } return nil @@ -189,7 +189,7 @@ func runAliasListCommand(cmd *cobra.Command, args []string) error { allAliases := cfg.Aliases if len(allAliases) == 0 { out.Println("No aliases registered.") - out.Println("\nCreate an alias with: cagent alias add ") + out.Println("\nCreate an alias with: docker agent alias add ") return nil } @@ -231,7 +231,7 @@ func runAliasListCommand(cmd *cobra.Command, args []string) error { } } - out.Println("\nRun an alias with: cagent run ") + out.Println("\nRun an alias with: docker agent run ") return nil } diff --git a/cmd/root/api.go b/cmd/root/api.go index 247dbf9a3..4721d16ff 100644 --- a/cmd/root/api.go +++ b/cmd/root/api.go @@ -31,8 +31,7 @@ func newAPICmd() *cobra.Command { cmd := &cobra.Command{ Use: "api |", - Short: "Start the cagent API server", - Long: `Start the API server that exposes the agent via a cagent-specific HTTP API`, + Short: "Start the API server", Args: cobra.ExactArgs(1), RunE: flags.runAPICommand, } diff --git a/cmd/root/mcp.go b/cmd/root/mcp.go index 203c0b578..c041a63a4 100644 --- a/cmd/root/mcp.go +++ b/cmd/root/mcp.go @@ -22,10 +22,10 @@ func newMCPCmd() *cobra.Command { Use: "mcp |", Short: "Start an agent as an MCP (Model Context Protocol) server", Long: "Start an MCP server that exposes the agent via the Model Context Protocol. By default, uses stdio transport. Use --http to start a streaming HTTP server instead.", - Example: ` cagent serve mcp ./agent.yaml - cagent serve mcp ./team.yaml - cagent serve mcp agentcatalog/pirate - cagent serve mcp ./agent.yaml --http --listen 127.0.0.1:9090`, + Example: ` docker-agent serve mcp ./agent.yaml + docker-agent serve mcp ./team.yaml + docker-agent serve mcp agentcatalog/pirate + docker-agent serve mcp ./agent.yaml --http --listen 127.0.0.1:9090`, Args: cobra.ExactArgs(1), RunE: flags.runMCPCommand, } diff --git a/cmd/root/new.go b/cmd/root/new.go index 9df20cd8f..ea75e68a1 100644 --- a/cmd/root/new.go +++ b/cmd/root/new.go @@ -33,12 +33,12 @@ func newNewCmd() *cobra.Command { Long: `Create a new agent configuration interactively. The agent builder will ask questions about what you want the agent to do, -then generate a YAML configuration file you can use with 'cagent run'. +then generate a YAML configuration file you can use with 'docker-agent run'. Optionally provide a description as an argument to skip the initial prompt.`, - Example: ` cagent new - cagent new "a web scraper that extracts product prices" - cagent new --model openai/gpt-4o "a code reviewer agent"`, + Example: ` docker-agent new + docker-agent new "a web scraper that extracts product prices" + docker-agent new --model openai/gpt-4o "a code reviewer agent"`, GroupID: "core", RunE: flags.runNewCommand, } diff --git a/cmd/root/root.go b/cmd/root/root.go index f1284ac18..b67142036 100644 --- a/cmd/root/root.go +++ b/cmd/root/root.go @@ -3,21 +3,19 @@ package root import ( "cmp" "context" - "errors" "fmt" "io" "log/slog" "os" "path/filepath" - "runtime" "strings" + "github.com/docker/cli/cli" "github.com/docker/cli/cli-plugins/metadata" "github.com/docker/cli/cli-plugins/plugin" "github.com/docker/cli/cli/command" "github.com/spf13/cobra" - "github.com/docker/cagent/pkg/environment" "github.com/docker/cagent/pkg/feedback" "github.com/docker/cagent/pkg/logging" "github.com/docker/cagent/pkg/paths" @@ -35,35 +33,50 @@ type rootFlags struct { dataDir string } -func isDockerAgent() bool { - cliPluginBinary := "docker-agent" - if runtime.GOOS == "windows" { - cliPluginBinary += ".exe" - } - return len(os.Args) > 0 && strings.HasSuffix(os.Args[0], cliPluginBinary) -} - func NewRootCmd() *cobra.Command { var flags rootFlags cmd := &cobra.Command{ - Use: "cagent", - Short: "cagent - AI agent runner", - Long: "cagent is a command-line tool for running AI agents", - Example: ` cagent run - cagent run ./agent.yaml - cagent run agentcatalog/pirate`, + Use: "docker-agent", + Short: "Docker AI Agent Runner", + Example: ` docker-agent run + docker-agent run ./agent.yaml + docker-agent run agentcatalog/pirate`, PersistentPreRunE: func(cmd *cobra.Command, args []string) error { // Apply directory overrides before anything else so that // logging, telemetry, and config loading honour them. - if flags.cacheDir != "" { - paths.SetCacheDir(flags.cacheDir) + if dir := flags.cacheDir; dir != "" { + paths.SetCacheDir(dir) } - if flags.configDir != "" { - paths.SetConfigDir(flags.configDir) + if dir := flags.configDir; dir != "" { + paths.SetConfigDir(dir) } - if flags.dataDir != "" { - paths.SetDataDir(flags.dataDir) + if dir := flags.dataDir; dir != "" { + paths.SetDataDir(dir) + } + + // Set the version for automatic telemetry initialization + telemetry.SetGlobalTelemetryVersion(version.Version) + + // Print startup message only on first installation/setup + if isFirstRun() && os.Getenv("CAGENT_HIDE_TELEMETRY_BANNER") != "1" && os.Getenv("DOCKER_AGENT_HIDE_TELEMETRY_BANNER") != "1" { + welcomeMsg := fmt.Sprintf(` +Welcome to docker agent! 🚀 + +For any feedback, please visit: %s +`, feedback.Link) + fmt.Fprint(cmd.ErrOrStderr(), welcomeMsg) + + // Only show telemetry notice when telemetry is enabled + if telemetry.GetTelemetryEnabled() { + telemetryMsg := ` +We collect anonymous usage data to help improve docker agent. To disable: + - Set environment variable: TELEMETRY_ENABLED=false +` + fmt.Fprint(cmd.ErrOrStderr(), telemetryMsg) + } + + fmt.Fprintln(cmd.ErrOrStderr()) } // Initialize logging before anything else so logs don't break TUI @@ -99,12 +112,26 @@ func NewRootCmd() *cobra.Command { } return nil }, - // If no subcommand is specified, show help RunE: func(cmd *cobra.Command, args []string) error { - return cmd.Help() + // Default to "run" command + if len(args) == 0 { + runCmd, _, _ := cmd.Find([]string{"run"}) + return runCmd.RunE(runCmd, nil) + } + + // Or print help + if args[0] == "help" { + return cmd.Help() + } + + // Or print help and an unknown command error + _ = cmd.Help() + return cli.StatusError{ + StatusCode: 1, + Status: fmt.Sprintf("ERROR: unknown command: %q", args[0]), + } }, - SilenceErrors: true, - SilenceUsage: true, + SilenceUsage: true, } // Add persistent debug flag available to all commands @@ -115,98 +142,63 @@ func NewRootCmd() *cobra.Command { cmd.PersistentFlags().StringVar(&flags.configDir, "config-dir", "", "Override the config directory (default: ~/.config/cagent)") cmd.PersistentFlags().StringVar(&flags.dataDir, "data-dir", "", "Override the data directory (default: ~/.cagent)") - cmd.AddCommand(newVersionCmd()) - cmd.AddCommand(newRunCmd()) - cmd.AddCommand(newNewCmd()) - cmd.AddCommand(newEvalCmd()) - cmd.AddCommand(newShareCmd()) - cmd.AddCommand(newDebugCmd()) - cmd.AddCommand(newAliasCmd()) - cmd.AddCommand(newServeCmd()) - // Define groups - cmd.AddGroup(&cobra.Group{ID: "core", Title: "Core Commands:"}) - cmd.AddGroup(&cobra.Group{ID: "advanced", Title: "Advanced Commands:"}) - - if isDockerAgent() && !plugin.RunningStandalone() { - cmd.Use = "agent" - cmd.Short = "create or run AI agents" - cmd.Long = "create or run AI agents" - cmd.Example = ` docker agent run ./agent.yaml - docker agent run agentcatalog/pirate` - } - if isDockerAgent() && plugin.RunningStandalone() { - cmd.Use = "docker-agent" - cmd.Short = "create or run AI agents" - cmd.Long = "create or run AI agents" - cmd.Example = ` docker-agent run ./agent.yaml - docker-agent run agentcatalog/pirate` - } + cmd.AddGroup( + &cobra.Group{ID: "core", Title: "Core Commands:"}, + &cobra.Group{ID: "advanced", Title: "Advanced Commands:"}, + ) + + cmd.AddCommand( + newVersionCmd(), + newRunCmd(), + newNewCmd(), + newEvalCmd(), + newShareCmd(), + newDebugCmd(), + newAliasCmd(), + newServeCmd(), + ) return cmd } func Execute(ctx context.Context, stdin io.Reader, stdout, stderr io.Writer, args ...string) error { - // Set the version for automatic telemetry initialization - telemetry.SetGlobalTelemetryVersion(version.Version) - - // Print startup message only on first installation/setup - if isFirstRun() && os.Getenv("CAGENT_HIDE_TELEMETRY_BANNER") != "1" && os.Getenv("DOCKER_AGENT_HIDE_TELEMETRY_BANNER") != "1" { - welcomeMsg := fmt.Sprintf(` -Welcome to docker agent! 🚀 - -For any feedback, please visit: %s -`, feedback.Link) - fmt.Fprint(stderr, welcomeMsg) - - // Only show telemetry notice when telemetry is enabled - if telemetry.GetTelemetryEnabled() { - telemetryMsg := ` -We collect anonymous usage data to help improve docker agent. To disable: - - Set environment variable: TELEMETRY_ENABLED=false -` - fmt.Fprint(stderr, telemetryMsg) - } - - fmt.Fprintln(stderr) - } - rootCmd := NewRootCmd() rootCmd.SetIn(stdin) rootCmd.SetOut(stdout) rootCmd.SetErr(stderr) - setContextRecursive(ctx, rootCmd) + rootCmd.SetArgs(args) - // when running 'docker ai', env vars are set for cli plugin and RunningStandalone is false, but ai shells out to cagent - // if the command is 'cagent' we want to run cagent standalone (there's no 'docker cagent') - if plugin.RunningStandalone() || rootCmd.Name() == "cagent" { - // When no subcommand is given, default to "run". - rootCmd.SetArgs(defaultToRun(rootCmd, args)) + runningStandalone := plugin.RunningStandalone() - if err := rootCmd.Execute(); err != nil { - return processErr(ctx, err, stderr, rootCmd) + visitAll(rootCmd, func(cmd *cobra.Command) { + cmd.SetContext(ctx) + if !runningStandalone { + cmd.Example = strings.ReplaceAll(cmd.Example, "docker-agent", "docker agent") } - return nil + }) + + if runningStandalone { + return rootCmd.Execute() } - // When no subcommand is given, default to "run". - rootCmd.SetArgs(append(args[0:1], defaultToRun(rootCmd, args[1:])...)) - os.Args = append(os.Args[0:2], defaultToRun(rootCmd, os.Args[2:])...) + plugin.Run(func(command.Cli) *cobra.Command { + // Force to the name of the docker command + rootCmd.Use = "agent" + + // Force default usage template. Otherwise it gets overridden by docker's. + rootCmd.SetUsageTemplate(rootCmd.UsageTemplate()) - plugin.Run(func(dockerCli command.Cli) *cobra.Command { originalPreRun := rootCmd.PersistentPreRunE rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { if err := plugin.PersistentPreRunE(cmd, args); err != nil { return err } if originalPreRun != nil { - if err := originalPreRun(cmd, args); err != nil { - return processErr(cmd.Context(), err, stderr, rootCmd) - } + return originalPreRun(cmd, args) } return nil } - setErrorHandlingRecursive(rootCmd, processErr) return rootCmd }, metadata.Metadata{ SchemaVersion: "0.1.0", @@ -217,90 +209,13 @@ We collect anonymous usage data to help improve docker agent. To disable: return nil } -func setContextRecursive(ctx context.Context, cmd *cobra.Command) { - cmd.SetContext(ctx) - for _, child := range cmd.Commands() { - setContextRecursive(ctx, child) - } -} - -func setErrorHandlingRecursive(cmd *cobra.Command, processErr func(context.Context, error, io.Writer, *cobra.Command) error) { - if cmd.RunE != nil { - originalRunE := cmd.RunE - cmd.RunE = func(cmd *cobra.Command, args []string) error { - if err := originalRunE(cmd, args); err != nil { - return processErr(cmd.Context(), err, cmd.ErrOrStderr(), cmd) - } - return nil - } - } - - for _, child := range cmd.Commands() { - setErrorHandlingRecursive(child, processErr) +func visitAll(cmd *cobra.Command, fn func(*cobra.Command)) { + fn(cmd) + for _, cmd := range cmd.Commands() { + visitAll(cmd, fn) } } -// defaultToRun prepends "run" to the argument list when no subcommand is -// specified so that bare "cagent" (or "cagent --debug", etc.) launches the -// default agent. Help flags (--help / -h) are left alone. -func defaultToRun(rootCmd *cobra.Command, args []string) []string { - for _, arg := range args { - switch { - case arg == "--": - // End of flags – no subcommand found. - return append([]string{"run"}, args...) - case arg == "--help" || arg == "-h": - return args - case strings.HasPrefix(arg, "-"): - continue - case isSubcommand(rootCmd, arg): - return args - default: - return append([]string{"run"}, args...) - } - } - - return append([]string{"run"}, args...) -} - -// isSubcommand reports whether name matches a registered subcommand or alias. -func isSubcommand(cmd *cobra.Command, name string) bool { - switch name { - case "help", "completion", "__complete", "__completeNoDesc": - return true - } - for _, sub := range cmd.Commands() { - if sub.Name() == name || sub.HasAlias(name) { - return true - } - } - return false -} - -func processErr(ctx context.Context, err error, stderr io.Writer, rootCmd *cobra.Command) error { - if ctx.Err() != nil { - return ctx.Err() - } else if envErr, ok := errors.AsType[*environment.RequiredEnvError](err); ok { - fmt.Fprintln(stderr, "The following environment variables must be set:") - for _, v := range envErr.Missing { - fmt.Fprintf(stderr, " - %s\n", v) - } - fmt.Fprintln(stderr, "\nEither:\n - Set those environment variables before running cagent\n - Run cagent with --env-from-file\n - Store those secrets using one of the built-in environment variable providers.") - } else if _, ok := errors.AsType[RuntimeError](err); ok { - // Runtime errors have already been printed by the command itself - // Don't print them again or show usage - } else { - // Command line usage errors - show the error and usage - fmt.Fprintln(stderr, err) - fmt.Fprintln(stderr) - if strings.HasPrefix(err.Error(), "unknown command ") || strings.HasPrefix(err.Error(), "accepts ") { - _ = rootCmd.Usage() - } - } - - return err -} - // setupLogging configures slog logging behavior. // When --debug is enabled, logs are written to a rotating file /cagent.debug.log, // or to the file specified by --log-file. Log files are rotated when they exceed 10MB, @@ -337,7 +252,7 @@ func (e RuntimeError) Unwrap() error { return e.Err } -// isFirstRun checks if this is the first time cagent is being run. +// isFirstRun checks if this is the first time docker agent is being run. // It atomically creates a marker file in the user's config directory // using os.O_EXCL to avoid a race condition when multiple processes // start concurrently. diff --git a/cmd/root/root_test.go b/cmd/root/root_test.go deleted file mode 100644 index 07f7abc98..000000000 --- a/cmd/root/root_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package root - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestDefaultToRun(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - args []string - want []string - }{ - { - name: "no args defaults to run", - args: []string{}, - want: []string{"run"}, - }, - { - name: "nil args defaults to run", - args: nil, - want: []string{"run"}, - }, - { - name: "known subcommand kept as-is", - args: []string{"version"}, - want: []string{"version"}, - }, - { - name: "run subcommand kept as-is", - args: []string{"run", "./agent.yaml"}, - want: []string{"run", "./agent.yaml"}, - }, - { - name: "help subcommand kept as-is", - args: []string{"help"}, - want: []string{"help"}, - }, - { - name: "--help flag kept as-is", - args: []string{"--help"}, - want: []string{"--help"}, - }, - { - name: "-h flag kept as-is", - args: []string{"-h"}, - want: []string{"-h"}, - }, - { - name: "only flags defaults to run", - args: []string{"--debug"}, - want: []string{"run", "--debug"}, - }, - { - name: "flags with agent file defaults to run", - args: []string{"--debug", "./agent.yaml"}, - want: []string{"run", "--debug", "./agent.yaml"}, - }, - { - name: "agent file without subcommand defaults to run", - args: []string{"./agent.yaml"}, - want: []string{"run", "./agent.yaml"}, - }, - { - name: "new subcommand kept as-is", - args: []string{"new"}, - want: []string{"new"}, - }, - { - name: "serve subcommand kept as-is", - args: []string{"serve", "mcp", "./agent.yaml"}, - want: []string{"serve", "mcp", "./agent.yaml"}, - }, - { - name: "debug and help still shows help", - args: []string{"--debug", "--help"}, - want: []string{"--debug", "--help"}, - }, - { - name: "agent file with flags defaults to run", - args: []string{"./agent.yaml", "--yolo"}, - want: []string{"run", "./agent.yaml", "--yolo"}, - }, - { - name: "__complete kept as-is for shell completion", - args: []string{"__complete", "run", ""}, - want: []string{"__complete", "run", ""}, - }, - { - name: "__completeNoDesc kept as-is for shell completion", - args: []string{"__completeNoDesc", "run", ""}, - want: []string{"__completeNoDesc", "run", ""}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - got := defaultToRun(NewRootCmd(), tt.args) - assert.Equal(t, tt.want, got) - }) - } -} diff --git a/cmd/root/run.go b/cmd/root/run.go index e560eb675..e2963139a 100644 --- a/cmd/root/run.go +++ b/cmd/root/run.go @@ -69,14 +69,14 @@ func newRunCmd() *cobra.Command { Use: "run [|] [message]...", Short: "Run an agent", Long: "Run an agent with the specified configuration and prompt", - Example: ` cagent run ./agent.yaml - cagent run ./team.yaml --agent root - cagent run # built-in default agent - cagent run coder # built-in coding agent - cagent run ./echo.yaml "INSTRUCTIONS" - cagent run ./echo.yaml "First question" "Follow-up question" - echo "INSTRUCTIONS" | cagent run ./echo.yaml - - cagent run ./agent.yaml --record # Records session to auto-generated file`, + Example: ` docker-agent run ./agent.yaml + docker-agent run ./team.yaml --agent root + docker-agent run # built-in default agent + docker-agent run coder # built-in coding agent + docker-agent run ./echo.yaml "INSTRUCTIONS" + docker-agent run ./echo.yaml "First question" "Follow-up question" + echo "INSTRUCTIONS" | docker-agent run ./echo.yaml - + docker-agent run ./agent.yaml --record # Records session to auto-generated file`, GroupID: "core", ValidArgsFunction: completeRunExec, Args: cobra.ArbitraryArgs, diff --git a/cmd/root/sandbox.go b/cmd/root/sandbox.go index 5d50316f8..4cc9b8e57 100644 --- a/cmd/root/sandbox.go +++ b/cmd/root/sandbox.go @@ -18,7 +18,7 @@ import ( // runInSandbox delegates the current command to a Docker sandbox. // It ensures a sandbox exists (creating or recreating as needed), then -// executes cagent inside it via `docker sandbox exec`. +// executes docker agent inside it via `docker sandbox exec`. func runInSandbox(cmd *cobra.Command, runConfig *config.RuntimeConfig, template string) error { if environment.InSandbox() { return fmt.Errorf("already running inside a Docker sandbox (VM %s)", os.Getenv("SANDBOX_VM_ID")) @@ -34,7 +34,7 @@ func runInSandbox(cmd *cobra.Command, runConfig *config.RuntimeConfig, template configDir := paths.GetConfigDir() // Always forward config directory paths so the sandbox-side - // cagent resolves it to the same host directories + // docker agent resolves it to the same host directories // (which is mounted read-write by ensureSandbox). cagentArgs = sandbox.AppendFlagIfMissing(cagentArgs, "--config-dir", configDir) diff --git a/e2e/binary/binary_test.go b/e2e/binary/binary_test.go index 8415304a1..752adb2d6 100644 --- a/e2e/binary/binary_test.go +++ b/e2e/binary/binary_test.go @@ -18,12 +18,6 @@ func TestHelpInAllExecMode(t *testing.T) { require.Contains(t, res.Stdout, "docker agent run ./agent.yaml") }) - t.Run("cagent help", func(t *testing.T) { - res, err := Exec(binDir+"/cagent", "help") - require.NoError(t, err) - require.Contains(t, res.Stdout, "cagent run ./agent.yaml") - }) - t.Run("docker-agent help", func(t *testing.T) { res, err := Exec(binDir+"/docker-agent", "help") require.NoError(t, err) @@ -39,13 +33,6 @@ func TestExecMissingKeys(t *testing.T) { require.Contains(t, res.Stderr, "OPENAI_API_KEY") }) - t.Run("cagent exec", func(t *testing.T) { - res, err := Exec(binDir+"/cagent", "run", "--exec", "./test-agent.yaml") - require.Error(t, err) - require.Contains(t, res.Stderr, "environment variables must be set") - require.Contains(t, res.Stderr, "OPENAI_API_KEY") - }) - t.Run("docker-agent exec", func(t *testing.T) { res, err := Exec(binDir+"/docker-agent", "run", "--exec", "./test-agent.yaml") require.Error(t, err) diff --git a/e2e/cagent_debug_test.go b/e2e/cagent_debug_test.go index 20a229337..bb6fa438a 100644 --- a/e2e/cagent_debug_test.go +++ b/e2e/cagent_debug_test.go @@ -9,7 +9,7 @@ import ( func TestDebug_Toolsets_None(t *testing.T) { t.Parallel() - output := cagent(t, "debug", "toolsets", "testdata/no_tools.yaml") + output := runCLI(t, "debug", "toolsets", "testdata/no_tools.yaml") require.Equal(t, "No tools for root\n", output) } @@ -17,7 +17,7 @@ func TestDebug_Toolsets_None(t *testing.T) { func TestDebug_Toolsets_Todo(t *testing.T) { t.Parallel() - output := cagent(t, "debug", "toolsets", "testdata/todo_tools.yaml") + output := runCLI(t, "debug", "toolsets", "testdata/todo_tools.yaml") require.Equal(t, "2 tool(s) for root:\n + create_todo - Create a new todo item with a description\n + list_todos - List all current todos with their status\n", output) } diff --git a/e2e/cagent_debug_title_test.go b/e2e/cagent_debug_title_test.go index 1e7a01669..12696e08c 100644 --- a/e2e/cagent_debug_title_test.go +++ b/e2e/cagent_debug_title_test.go @@ -33,7 +33,7 @@ func TestDebug_Title(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - title := cagent(t, "debug", "title", "testdata/basic.yaml", "--model="+tt.model, "What can you do?") + title := runCLI(t, "debug", "title", "testdata/basic.yaml", "--model="+tt.model, "What can you do?") assert.Equal(t, tt.want, title) }) diff --git a/e2e/cagent_exec_test.go b/e2e/cagent_exec_test.go index 3d22cc47f..17afa7345 100644 --- a/e2e/cagent_exec_test.go +++ b/e2e/cagent_exec_test.go @@ -7,7 +7,7 @@ import ( ) func TestExec_OpenAI(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/basic.yaml", "What's 2+2?") + out := runCLI(t, "run", "--exec", "testdata/basic.yaml", "What's 2+2?") require.Equal(t, "\n--- Agent: root ---\n2 + 2 equals 4.", out) } @@ -15,7 +15,7 @@ func TestExec_OpenAI(t *testing.T) { // TestExec_OpenAI_V3Config tests that v3 configs work correctly with thinking disabled by default. // This uses gpt-5 with a v3 config file to verify thinking is disabled for old config versions. func TestExec_OpenAI_V3Config(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/basic_v3.yaml", "What's 2+2?") + out := runCLI(t, "run", "--exec", "testdata/basic_v3.yaml", "What's 2+2?") // v3 config with gpt-5 should work correctly (thinking disabled by default for old configs) require.Equal(t, "\n--- Agent: root ---\n4", out) @@ -24,7 +24,7 @@ func TestExec_OpenAI_V3Config(t *testing.T) { // TestExec_OpenAI_WithThinkingBudget tests that when thinking_budget is explicitly configured // in the YAML, thinking is enabled by default (without needing /think command). func TestExec_OpenAI_WithThinkingBudget(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/basic_with_thinking.yaml", "What's 2+2?") + out := runCLI(t, "run", "--exec", "testdata/basic_with_thinking.yaml", "What's 2+2?") // With thinking_budget explicitly configured, response should include reasoning // The output format includes the reasoning summary when thinking is enabled @@ -33,19 +33,19 @@ func TestExec_OpenAI_WithThinkingBudget(t *testing.T) { } func TestExec_OpenAI_ToolCall(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/fs_tools.yaml", "How many files in testdata/working_dir? Only output the number.") + out := runCLI(t, "run", "--exec", "testdata/fs_tools.yaml", "How many files in testdata/working_dir? Only output the number.") require.Equal(t, "\n--- Agent: root ---\n\nCalling list_directory(path: \"testdata/working_dir\")\n\nlist_directory response → \"FILE README.me\\n\"\n1", out) } func TestExec_OpenAI_HideToolCalls(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/fs_tools.yaml", "--hide-tool-calls", "How many files in testdata/working_dir? Only output the number.") + out := runCLI(t, "run", "--exec", "testdata/fs_tools.yaml", "--hide-tool-calls", "How many files in testdata/working_dir? Only output the number.") require.Equal(t, "\n--- Agent: root ---\n1", out) } func TestExec_OpenAI_gpt5(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/basic.yaml", "--model=openai/gpt-5", "What's 2+2?") + out := runCLI(t, "run", "--exec", "testdata/basic.yaml", "--model=openai/gpt-5", "What's 2+2?") // With thinking enabled by default, response may include reasoning summary require.Contains(t, out, "--- Agent: root ---") @@ -53,13 +53,13 @@ func TestExec_OpenAI_gpt5(t *testing.T) { } func TestExec_OpenAI_gpt5_1(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/basic.yaml", "--model=openai/gpt-5.1", "What's 2+2?") + out := runCLI(t, "run", "--exec", "testdata/basic.yaml", "--model=openai/gpt-5.1", "What's 2+2?") require.Equal(t, "\n--- Agent: root ---\n2 + 2 = 4.", out) } func TestExec_OpenAI_gpt5_codex(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/basic.yaml", "--model=openai/gpt-5-codex", "What's 2+2?") + out := runCLI(t, "run", "--exec", "testdata/basic.yaml", "--model=openai/gpt-5-codex", "What's 2+2?") // Model reasoning summary varies, just check for the core response require.Contains(t, out, "--- Agent: root ---") @@ -67,7 +67,7 @@ func TestExec_OpenAI_gpt5_codex(t *testing.T) { } func TestExec_Anthropic(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/basic.yaml", "--model=anthropic/claude-sonnet-4-0", "What's 2+2?") + out := runCLI(t, "run", "--exec", "testdata/basic.yaml", "--model=anthropic/claude-sonnet-4-0", "What's 2+2?") // With interleaved thinking enabled by default, Anthropic responses include thinking content require.Contains(t, out, "--- Agent: root ---") @@ -75,7 +75,7 @@ func TestExec_Anthropic(t *testing.T) { } func TestExec_Anthropic_ToolCall(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/fs_tools.yaml", "--model=anthropic/claude-sonnet-4-0", "How many files in testdata/working_dir? Only output the number.") + out := runCLI(t, "run", "--exec", "testdata/fs_tools.yaml", "--model=anthropic/claude-sonnet-4-0", "How many files in testdata/working_dir? Only output the number.") // With interleaved thinking enabled by default, Anthropic responses include thinking content require.Contains(t, out, "--- Agent: root ---") @@ -86,7 +86,7 @@ func TestExec_Anthropic_ToolCall(t *testing.T) { } func TestExec_Anthropic_AgentsMd(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/agents-md.yaml", "--model=anthropic/claude-sonnet-4-0", "What's 2+2?") + out := runCLI(t, "run", "--exec", "testdata/agents-md.yaml", "--model=anthropic/claude-sonnet-4-0", "What's 2+2?") // With interleaved thinking enabled by default, Anthropic responses include thinking content require.Contains(t, out, "--- Agent: root ---") @@ -94,7 +94,7 @@ func TestExec_Anthropic_AgentsMd(t *testing.T) { } func TestExec_Gemini(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/basic.yaml", "--model=google/gemini-2.5-flash", "What's 2+2?") + out := runCLI(t, "run", "--exec", "testdata/basic.yaml", "--model=google/gemini-2.5-flash", "What's 2+2?") // With thinking enabled by default (dynamic thinking for Gemini 2.5), responses may include thinking content require.Contains(t, out, "--- Agent: root ---") @@ -103,7 +103,7 @@ func TestExec_Gemini(t *testing.T) { } func TestExec_Gemini_ToolCall(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/fs_tools.yaml", "--model=google/gemini-2.5-flash", "How many files in testdata/working_dir? Only output the number.") + out := runCLI(t, "run", "--exec", "testdata/fs_tools.yaml", "--model=google/gemini-2.5-flash", "How many files in testdata/working_dir? Only output the number.") // With thinking enabled by default (dynamic thinking for Gemini 2.5), responses include thinking content require.Contains(t, out, "--- Agent: root ---") @@ -114,19 +114,19 @@ func TestExec_Gemini_ToolCall(t *testing.T) { } func TestExec_Mistral(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/basic.yaml", "--model=mistral/mistral-small", "What's 2+2?") + out := runCLI(t, "run", "--exec", "testdata/basic.yaml", "--model=mistral/mistral-small", "What's 2+2?") require.Equal(t, "\n--- Agent: root ---\nThe sum of 2 + 2 is 4.", out) } func TestExec_Mistral_ToolCall(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/fs_tools.yaml", "--model=mistral/mistral-small", "How many files in testdata/working_dir? Only output the number.") + out := runCLI(t, "run", "--exec", "testdata/fs_tools.yaml", "--model=mistral/mistral-small", "How many files in testdata/working_dir? Only output the number.") require.Equal(t, "\n--- Agent: root ---\n\nCalling list_directory(path: \"testdata/working_dir\")\n\nlist_directory response → \"FILE README.me\\n\"\n1", out) } func TestExec_ToolCallsNeedAcceptance(t *testing.T) { - out := cagent(t, "run", "--exec", "testdata/file_writer.yaml", "Create a hello.txt file with \"Hello, World!\" content. Try only once. On error, exit without further message.") + out := runCLI(t, "run", "--exec", "testdata/file_writer.yaml", "Create a hello.txt file with \"Hello, World!\" content. Try only once. On error, exit without further message.") require.Contains(t, out, `Can I run this tool? ([y]es/[a]ll/[n]o)`) } diff --git a/e2e/helpers_test.go b/e2e/helpers_test.go index 48a5dbca2..f5c7d2676 100644 --- a/e2e/helpers_test.go +++ b/e2e/helpers_test.go @@ -12,11 +12,11 @@ import ( "github.com/docker/cagent/cmd/root" ) -// cagent runs a cagent CLI command and returns its stdout. +// runCLI runs a docker agent CLI command and returns its stdout. // The first argument is the command name ("exec", "debug", etc.). // Commands that talk to an AI model ("exec", "debug title") automatically // get a recording AI proxy. The "exec" command also gets a unique session DB. -func cagent(t *testing.T, command string, moreArgs ...string) string { +func runCLI(t *testing.T, command string, moreArgs ...string) string { t.Helper() args := []string{command} diff --git a/pkg/a2a/adapter.go b/pkg/a2a/adapter.go index 107f78145..84ea5a9c2 100644 --- a/pkg/a2a/adapter.go +++ b/pkg/a2a/adapter.go @@ -11,13 +11,13 @@ import ( adksession "google.golang.org/adk/session" "google.golang.org/genai" - cagent "github.com/docker/cagent/pkg/agent" + dagent "github.com/docker/cagent/pkg/agent" "github.com/docker/cagent/pkg/runtime" "github.com/docker/cagent/pkg/session" "github.com/docker/cagent/pkg/team" ) -// newCAgentAdapter creates a new ADK agent adapter from a cagent team and agent name +// newCAgentAdapter creates a new ADK agent adapter from a docker agent team and agent name func newCAgentAdapter(t *team.Team, agentName string) (agent.Agent, error) { a, err := t.Agent(agentName) if err != nil { @@ -35,14 +35,14 @@ func newCAgentAdapter(t *team.Team, agentName string) (agent.Agent, error) { }) } -// runCAgent executes a cagent agent and returns ADK session events -func runCAgent(ctx agent.InvocationContext, t *team.Team, agentName string, a *cagent.Agent) iter.Seq2[*adksession.Event, error] { +// runCAgent executes a docker agent and returns ADK session events +func runCAgent(ctx agent.InvocationContext, t *team.Team, agentName string, a *dagent.Agent) iter.Seq2[*adksession.Event, error] { return func(yield func(*adksession.Event, error) bool) { // Extract user message from the ADK context userContent := ctx.UserContent() message := contentToMessage(userContent) - // Create a cagent session + // Create a session sess := session.New( session.WithUserMessage(message), session.WithMaxIterations(a.MaxIterations()), @@ -64,7 +64,7 @@ func runCAgent(ctx agent.InvocationContext, t *team.Team, agentName string, a *c // Track accumulated content for chunked responses var contentBuilder string - // Convert cagent events to ADK events and yield them + // Convert docker agent events to ADK events and yield them for event := range eventsChan { if ctx.Ended() { slog.Debug("Invocation ended, stopping agent", "agent", agentName) diff --git a/pkg/a2a/server.go b/pkg/a2a/server.go index 27f7a1ced..3f5aefe57 100644 --- a/pkg/a2a/server.go +++ b/pkg/a2a/server.go @@ -73,7 +73,7 @@ func Run(ctx context.Context, agentFilename, agentName string, runConfig *config ID: fmt.Sprintf("%s_%s", name, agentName), Name: agentName, Description: adkAgent.Description(), - Tags: []string{"llm", "cagent"}, + Tags: []string{"llm", "docker agent"}, }}, PreferredTransport: a2a.TransportProtocolJSONRPC, URL: baseURL.JoinPath(agentPath).String(), diff --git a/pkg/acp/agent.go b/pkg/acp/agent.go index 86666a306..68b745d4d 100644 --- a/pkg/acp/agent.go +++ b/pkg/acp/agent.go @@ -24,7 +24,7 @@ import ( "github.com/docker/cagent/pkg/version" ) -// Agent implements the ACP Agent interface for cagent +// Agent implements the ACP Agent interface for docker agent type Agent struct { agentSource config.Source runConfig *config.RuntimeConfig @@ -86,11 +86,11 @@ func (a *Agent) Initialize(ctx context.Context, params acp.InitializeRequest) (a a.team = t slog.Debug("Teams loaded successfully", "source", a.agentSource.Name(), "agent_count", t.Size()) - agentTitle := "cagent" + agentTitle := "docker agent" return acp.InitializeResponse{ ProtocolVersion: acp.ProtocolVersionNumber, AgentInfo: &acp.Implementation{ - Name: "cagent", + Name: "docker agent", Version: version.Version, Title: &agentTitle, }, @@ -362,7 +362,7 @@ func stringOrDefault(s *string, def string) string { // SetSessionMode implements acp.Agent (optional) func (a *Agent) SetSessionMode(context.Context, acp.SetSessionModeRequest) (acp.SetSessionModeResponse, error) { - // We don't implement session modes, cagent agents have only one mode (for now? ;) ). + // We don't implement session modes, agents have only one mode (for now? ;) ). return acp.SetSessionModeResponse{}, nil } @@ -803,7 +803,7 @@ func buildPlanUpdateFromTodos(meta any) *acp.SessionUpdate { return &update } -// mapTodoStatusToACP converts cagent todo status to ACP plan entry status +// mapTodoStatusToACP converts docker agent todo status to ACP plan entry status func mapTodoStatusToACP(status string) acp.PlanEntryStatus { switch status { case "pending": diff --git a/pkg/app/export/html.go b/pkg/app/export/html.go index dd5dd1568..bafe34911 100644 --- a/pkg/app/export/html.go +++ b/pkg/app/export/html.go @@ -1,4 +1,4 @@ -// Package export provides HTML export functionality for cagent sessions. +// Package export provides HTML export functionality for docker agent sessions. package export import ( @@ -341,7 +341,7 @@ func Generate(data SessionData) (string, error) { title := data.Title if title == "" { - title = "cagent Session" + title = "Docker Agent Session" } totalTokens := data.InputTokens + data.OutputTokens diff --git a/pkg/config/config.go b/pkg/config/config.go index ebd33c73a..1c6c50550 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -3,6 +3,7 @@ package config import ( "cmp" "context" + "errors" "fmt" "log/slog" "maps" @@ -53,6 +54,12 @@ func Load(ctx context.Context, source Source) (*latest.Config, error) { // // This allows exiting early with a proper error message instead of failing later when trying to use a model or tool. func CheckRequiredEnvVars(ctx context.Context, cfg *latest.Config, modelsGateway string, env environment.Provider) error { + if modelsGateway != "" { + if jwt, _ := env.Get(ctx, environment.DockerDesktopTokenEnv); jwt == "" { + return errors.New("sorry, you first need to sign in Docker Desktop to use the Docker AI Gateway") + } + } + missing, err := gatherMissingEnvVars(ctx, cfg, modelsGateway, env) if err != nil { // If there's a tool preflight error, log it but continue diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index cab81294e..7d40222a6 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -202,6 +202,15 @@ type noEnvProvider struct{} func (p *noEnvProvider) Get(context.Context, string) (string, bool) { return "", false } +type fakeEnvProvider struct { + vars map[string]string +} + +func (p *fakeEnvProvider) Get(_ context.Context, name string) (string, bool) { + v, ok := p.vars[name] + return v, ok +} + func TestCheckRequiredEnvVars(t *testing.T) { t.Parallel() @@ -282,12 +291,29 @@ func TestCheckRequiredEnvVars(t *testing.T) { func TestCheckRequiredEnvVarsWithModelGateway(t *testing.T) { t.Parallel() - cfg, err := Load(t.Context(), NewFileSource("testdata/env/all.yaml")) - require.NoError(t, err) + t.Run("with token", func(t *testing.T) { + t.Parallel() - err = CheckRequiredEnvVars(t.Context(), cfg, "gateway:8080", &noEnvProvider{}) + cfg, err := Load(t.Context(), NewFileSource("testdata/env/all.yaml")) + require.NoError(t, err) - require.NoError(t, err) + env := &fakeEnvProvider{vars: map[string]string{ + environment.DockerDesktopTokenEnv: "some-jwt-token", + }} + + err = CheckRequiredEnvVars(t.Context(), cfg, "gateway:8080", env) + require.NoError(t, err) + }) + + t.Run("without token", func(t *testing.T) { + t.Parallel() + + cfg, err := Load(t.Context(), NewFileSource("testdata/env/all.yaml")) + require.NoError(t, err) + + err = CheckRequiredEnvVars(t.Context(), cfg, "gateway:8080", &noEnvProvider{}) + require.ErrorContains(t, err, "sign in Docker Desktop") + }) } func TestApplyModelOverrides(t *testing.T) { diff --git a/pkg/config/latest/types.go b/pkg/config/latest/types.go index e5a969cd1..815971397 100644 --- a/pkg/config/latest/types.go +++ b/pkg/config/latest/types.go @@ -567,7 +567,7 @@ type Toolset struct { // For `mcp` and `lsp` tools - version/package reference for auto-installation. // Format: "owner/repo" or "owner/repo@version" - // When empty and auto-install is enabled, cagent auto-detects from the command name. + // When empty and auto-install is enabled, docker agent auto-detects from the command name. // Set to "false" or "off" to disable auto-install for this toolset. Version string `json:"version,omitempty"` diff --git a/pkg/connectrpc/server.go b/pkg/connectrpc/server.go index c06bb20ee..f0e29c877 100644 --- a/pkg/connectrpc/server.go +++ b/pkg/connectrpc/server.go @@ -1,4 +1,4 @@ -// Package connectrpc provides a Connect-RPC server implementation for the cagent API. +// Package connectrpc provides a Connect-RPC server implementation for the docker agent API. package connectrpc import ( diff --git a/pkg/environment/errors.go b/pkg/environment/errors.go index f2182b50c..3ee7d94ac 100644 --- a/pkg/environment/errors.go +++ b/pkg/environment/errors.go @@ -1,6 +1,9 @@ package environment -import "strings" +import ( + "fmt" + "strings" +) type RequiredEnvError struct { Missing []string @@ -9,5 +12,13 @@ type RequiredEnvError struct { var _ error = &RequiredEnvError{} func (e *RequiredEnvError) Error() string { - return "missing required environment variables: " + strings.Join(e.Missing, ", ") + var msg strings.Builder + + fmt.Fprintln(&msg, "The following environment variables must be set:") + for _, v := range e.Missing { + fmt.Fprintf(&msg, " - %s\n", v) + } + fmt.Fprintln(&msg, "\nEither:\n - Set those environment variables before running docker agent\n - Run docker agent with --env-from-file\n - Store those secrets using one of the built-in environment variable providers.") + + return msg.String() } diff --git a/pkg/environment/sandbox.go b/pkg/environment/sandbox.go index 922dfc447..f35d329ee 100644 --- a/pkg/environment/sandbox.go +++ b/pkg/environment/sandbox.go @@ -4,7 +4,7 @@ import "os" const sandboxVMIDEnv = "SANDBOX_VM_ID" -// InSandbox reports whether cagent is running inside a Docker sandbox. +// InSandbox reports whether docker agent is running inside a Docker sandbox. // Detection relies on the SANDBOX_VM_ID environment variable that Docker // Desktop sets in every sandbox VM. func InSandbox() bool { diff --git a/pkg/evaluation/eval.go b/pkg/evaluation/eval.go index f0f01b41f..5d40caf81 100644 --- a/pkg/evaluation/eval.go +++ b/pkg/evaluation/eval.go @@ -311,7 +311,7 @@ func (r *Runner) runSingleEval(ctx context.Context, evalSess *InputSession) (Res events, err := r.runCagentInContainer(ctx, imageID, getUserMessages(evalSess.Session), evals.Setup) if err != nil { - return result, fmt.Errorf("running cagent in container: %w", err) + return result, fmt.Errorf("running docker agent in container: %w", err) } response, cost, outputTokens, actualToolCalls := parseContainerEvents(events) @@ -397,7 +397,7 @@ func (r *Runner) runCagentInContainer(ctx context.Context, imageID string, quest } // When a setup script is provided, mount it into the container and - // override the entrypoint to run it before cagent run --exec. + // override the entrypoint to run it before docker agent run --exec. // The default entrypoint is: /run.sh /cagent run --exec --yolo --json // /run.sh starts dockerd then exec's "$@". if setup != "" { @@ -416,7 +416,7 @@ func (r *Runner) runCagentInContainer(ctx context.Context, imageID string, quest args = append(args, imageID) if setup != "" { - // Run setup script, then cagent run --exec with the original arguments. + // Run setup script, then docker agent run --exec with the original arguments. args = append(args, "sh", "-c", "sh /setup.sh && exec /cagent run --exec --yolo --json \"$@\"", "--", "/configs/"+agentFile) } else { args = append(args, "/configs/"+agentFile) diff --git a/pkg/evaluation/save.go b/pkg/evaluation/save.go index 40d9a0c60..8ef0add3a 100644 --- a/pkg/evaluation/save.go +++ b/pkg/evaluation/save.go @@ -53,7 +53,7 @@ func SaveRunSessions(ctx context.Context, run *EvalRun, outputDir string) (strin } // SessionFromEvents reconstructs a session from raw container output events. -// This parses the JSON events emitted by cagent --json and builds a session +// This parses the JSON events emitted by docker agent run --exec --json and builds a session // with the conversation history. func SessionFromEvents(events []map[string]any, title string, questions []string) *session.Session { sess := session.New( diff --git a/pkg/gateway/catalog.go b/pkg/gateway/catalog.go index bf9b807b8..6d058918f 100644 --- a/pkg/gateway/catalog.go +++ b/pkg/gateway/catalog.go @@ -25,7 +25,7 @@ func RequiredEnvVars(ctx context.Context, serverName string) ([]Secret, error) { return nil, err } - // TODO(dga): until the MCP Gateway supports oauth with cagent, + // TODO(dga): until the MCP Gateway supports oauth with docker agent, // we ignore every secret listed on `remote` servers and assume // we can use oauth by connecting directly to the server's url. if server.Type == "remote" { diff --git a/pkg/mcp/server.go b/pkg/mcp/server.go index 8f3dbe64e..41e982af9 100644 --- a/pkg/mcp/server.go +++ b/pkg/mcp/server.go @@ -100,7 +100,7 @@ func createMCPServer(ctx context.Context, agentFilename, agentName string, runCo } server := mcp.NewServer(&mcp.Implementation{ - Name: "cagent", + Name: "docker agent", Version: version.Version, }, nil) diff --git a/pkg/paths/paths.go b/pkg/paths/paths.go index 2047bb4c0..c54e1d46c 100644 --- a/pkg/paths/paths.go +++ b/pkg/paths/paths.go @@ -47,7 +47,7 @@ func SetConfigDir(dir string) { configDirOverride.Set(dir) } // An empty value restores the default behaviour. func SetDataDir(dir string) { dataDirOverride.Set(dir) } -// GetCacheDir returns the user's cache directory for cagent. +// GetCacheDir returns the user's cache directory for docker agent. // // If an override has been set via [SetCacheDir] it is returned instead. // @@ -67,7 +67,7 @@ func GetCacheDir() string { }) } -// GetConfigDir returns the user's config directory for cagent. +// GetConfigDir returns the user's config directory for docker agent. // // If an override has been set via [SetConfigDir] it is returned instead. // @@ -84,7 +84,7 @@ func GetConfigDir() string { }) } -// GetDataDir returns the user's data directory for cagent (caches, content, logs). +// GetDataDir returns the user's data directory for docker agent (caches, content, logs). // // If an override has been set via [SetDataDir] it is returned instead. // diff --git a/pkg/remote/pull.go b/pkg/remote/pull.go index f1c5f625e..818a7c006 100644 --- a/pkg/remote/pull.go +++ b/pkg/remote/pull.go @@ -34,7 +34,7 @@ func Pull(ctx context.Context, registryRef string, force bool, opts ...crane.Opt if meta, metaErr := store.GetArtifactMetadata(localRef); metaErr == nil { if meta.Digest == remoteDigest { if !hasCagentAnnotation(meta.Annotations) { - return "", fmt.Errorf("artifact %s found in store wasn't created by `cagent share push`\nTry to push again with `cagent share push` (cagent >= v1.10.0)", localRef) + return "", fmt.Errorf("artifact %s found in store wasn't created by `docker agent share push`\nTry to push again with `docker agent share push`", localRef) } return meta.Digest, nil } @@ -51,7 +51,7 @@ func Pull(ctx context.Context, registryRef string, force bool, opts ...crane.Opt return "", fmt.Errorf("getting manifest from pulled image: %w", err) } if !hasCagentAnnotation(manifest.Annotations) { - return "", fmt.Errorf("artifact %s wasn't created by `cagent share push`\nTry to push again with `cagent share push` (cagent >= v1.10.0)", localRef) + return "", fmt.Errorf("artifact %s wasn't created by `docker agent share push`\nTry to push again with `docker agent share push`", localRef) } digest, err := store.StoreArtifact(img, localRef) diff --git a/pkg/runtime/client.go b/pkg/runtime/client.go index c590ced7c..ab2fe226e 100644 --- a/pkg/runtime/client.go +++ b/pkg/runtime/client.go @@ -19,7 +19,7 @@ import ( "github.com/docker/cagent/pkg/tools" ) -// Client is an HTTP client for the cagent server API +// Client is an HTTP client for the docker agent server API type Client struct { baseURL *url.URL httpClient *http.Client @@ -46,7 +46,7 @@ func WithTimeout(timeout time.Duration) ClientOption { } } -// NewClient creates a new HTTP client for the cagent server +// NewClient creates a new HTTP client for the docker agent server func NewClient(baseURL string, opts ...ClientOption) (*Client, error) { parsedURL, err := url.Parse(baseURL) if err != nil { diff --git a/pkg/runtime/connectrpc_client.go b/pkg/runtime/connectrpc_client.go index 6ddf29992..f693a272e 100644 --- a/pkg/runtime/connectrpc_client.go +++ b/pkg/runtime/connectrpc_client.go @@ -20,7 +20,7 @@ import ( "github.com/docker/cagent/pkg/tools" ) -// ConnectRPCClient is a Connect-RPC client for the cagent server API +// ConnectRPCClient is a Connect-RPC client for the docker agent server API type ConnectRPCClient struct { client cagentv1connect.AgentServiceClient } @@ -39,7 +39,7 @@ func WithConnectRPCHTTPClient(client *http.Client) ConnectRPCClientOption { } } -// NewConnectRPCClient creates a new Connect-RPC client for the cagent server +// NewConnectRPCClient creates a new Connect-RPC client for the docker agent server func NewConnectRPCClient(baseURL string, opts ...ConnectRPCClientOption) (*ConnectRPCClient, error) { options := &connectRPCClientOptions{ httpClient: &http.Client{ diff --git a/pkg/runtime/model_switcher.go b/pkg/runtime/model_switcher.go index 75b9011f8..09b004b25 100644 --- a/pkg/runtime/model_switcher.go +++ b/pkg/runtime/model_switcher.go @@ -314,11 +314,11 @@ func (r *LocalRuntime) buildCatalogChoices(ctx context.Context) []ModelChoice { var choices []ModelChoice for providerID, prov := range db.Providers { // Check if this provider is supported and user has credentials - cagentProvider, supported := mapModelsDevProvider(providerID) + dockerAgentProvider, supported := mapModelsDevProvider(providerID) if !supported { continue } - if !availableProviders[cagentProvider] { + if !availableProviders[dockerAgentProvider] { continue } @@ -332,7 +332,7 @@ func (r *LocalRuntime) buildCatalogChoices(ctx context.Context) []ModelChoice { continue } - ref := cagentProvider + "/" + modelID + ref := dockerAgentProvider + "/" + modelID if existingRefs[ref] { continue } @@ -341,7 +341,7 @@ func (r *LocalRuntime) buildCatalogChoices(ctx context.Context) []ModelChoice { choices = append(choices, ModelChoice{ Name: model.Name, Ref: ref, - Provider: cagentProvider, + Provider: dockerAgentProvider, Model: modelID, IsCatalog: true, }) @@ -352,8 +352,8 @@ func (r *LocalRuntime) buildCatalogChoices(ctx context.Context) []ModelChoice { return choices } -// mapModelsDevProvider maps a models.dev provider ID to a cagent provider name. -// Returns the cagent provider name and whether it's supported. +// mapModelsDevProvider maps a models.dev provider ID to a docker agent provider name. +// Returns the docker agent provider name and whether it's supported. // Uses provider.IsCatalogProvider to dynamically include all core providers // and aliases with defined base URLs. func mapModelsDevProvider(providerID string) (string, bool) { diff --git a/pkg/runtime/remote_client.go b/pkg/runtime/remote_client.go index 7e2e912f3..473e574cb 100644 --- a/pkg/runtime/remote_client.go +++ b/pkg/runtime/remote_client.go @@ -10,7 +10,7 @@ import ( ) // RemoteClient is the interface that both HTTP and Connect-RPC clients implement -// for communicating with a remote cagent server. +// for communicating with a remote docker agent server. type RemoteClient interface { // GetAgent retrieves an agent configuration by ID GetAgent(ctx context.Context, id string) (*latest.Config, error) diff --git a/pkg/session/session.go b/pkg/session/session.go index bdbc56148..509a43bc0 100644 --- a/pkg/session/session.go +++ b/pkg/session/session.go @@ -223,7 +223,7 @@ type EvalCriteria struct { Relevance []string `json:"relevance"` // Statements that should be true about the response WorkingDir string `json:"working_dir,omitempty"` // Subdirectory under evals/working_dirs/ Size string `json:"size,omitempty"` // Expected response size: S, M, L, XL - Setup string `json:"setup,omitempty"` // Optional sh script to run in the container before cagent run --exec + Setup string `json:"setup,omitempty"` // Optional sh script to run in the container before docker agent run --exec } // deepCopyMessage returns a deep copy of a session Message. diff --git a/pkg/session/store.go b/pkg/session/store.go index 6cfd86d19..ef8df04d0 100644 --- a/pkg/session/store.go +++ b/pkg/session/store.go @@ -336,7 +336,7 @@ type SQLiteSessionStore struct { } // syncMessagesColumn rebuilds the messages JSON column from session_items for backward compatibility. -// This allows older versions of cagent to read sessions created by newer versions. +// This allows older versions of docker agent to read sessions created by newer versions. func (s *SQLiteSessionStore) syncMessagesColumn(ctx context.Context, sessionID string) error { return s.syncMessagesColumnWith(ctx, s.db, sessionID) } @@ -742,7 +742,7 @@ type sessionItemRow struct { // loadSessionItems loads all items for a session from the session_items table. // If no items exist in session_items, it falls back to the legacy messages JSON column -// for backward compatibility with sessions created by older cagent versions. +// for backward compatibility with sessions created by older docker agent versions. func (s *SQLiteSessionStore) loadSessionItems(ctx context.Context, sessionID string) ([]Item, error) { return s.loadSessionItemsWith(ctx, s.db, sessionID) } @@ -846,7 +846,7 @@ func (s *SQLiteSessionStore) loadSessionWith(ctx context.Context, q querier, id } // loadMessagesFromLegacyColumn loads messages from the legacy messages JSON column. -// This is used for backward compatibility with sessions created by older cagent versions +// This is used for backward compatibility with sessions created by older docker agent versions // that haven't been migrated to the session_items table yet. func (s *SQLiteSessionStore) loadMessagesFromLegacyColumn(ctx context.Context, sessionID string) ([]Item, error) { var messagesJSON sql.NullString @@ -1138,7 +1138,7 @@ func (s *SQLiteSessionStore) AddMessage(ctx context.Context, sessionID string, m return 0, fmt.Errorf("getting last insert id: %w", err) } - // Update messages column for backward compatibility with older cagent versions + // Update messages column for backward compatibility with older docker agent versions if err := s.syncMessagesColumn(ctx, sessionID); err != nil { slog.Warn("[STORE] Failed to sync messages column", "session_id", sessionID, "error", err) } @@ -1355,7 +1355,7 @@ func (s *SQLiteSessionStore) AddSummary(ctx context.Context, sessionID, summary return err } - // Update messages column for backward compatibility with older cagent versions + // Update messages column for backward compatibility with older docker agent versions if syncErr := s.syncMessagesColumn(ctx, sessionID); syncErr != nil { slog.Warn("[STORE] Failed to sync messages column", "session_id", sessionID, "error", syncErr) } diff --git a/pkg/session/store_test.go b/pkg/session/store_test.go index 0fe436aba..706d52d88 100644 --- a/pkg/session/store_test.go +++ b/pkg/session/store_test.go @@ -802,7 +802,7 @@ func TestBackupDatabase(t *testing.T) { } // TestBackwardCompatibility_ReadLegacyMessages verifies that new code can read -// sessions that were created by older cagent versions (messages in JSON column only). +// sessions that were created by older docker agent versions (messages in JSON column only). func TestBackwardCompatibility_ReadLegacyMessages(t *testing.T) { tempDB := filepath.Join(t.TempDir(), "test_legacy.db") @@ -847,7 +847,7 @@ func TestBackwardCompatibility_ReadLegacyMessages(t *testing.T) { } // TestForwardCompatibility_MessagesColumnPopulated verifies that new code populates -// the messages column so older cagent versions can read sessions. +// the messages column so older docker agent versions can read sessions. func TestForwardCompatibility_MessagesColumnPopulated(t *testing.T) { tempDB := filepath.Join(t.TempDir(), "test_forward.db") @@ -878,7 +878,7 @@ func TestForwardCompatibility_MessagesColumnPopulated(t *testing.T) { }) require.NoError(t, err) - // Verify messages column is populated (how old cagent would read it) + // Verify messages column is populated (how old docker agent would read it) var messagesJSON string err = sqliteStore.db.QueryRowContext(t.Context(), "SELECT messages FROM sessions WHERE id = ?", "new-session").Scan(&messagesJSON) diff --git a/pkg/teamloader/registry.go b/pkg/teamloader/registry.go index 0028a9837..6f410aa56 100644 --- a/pkg/teamloader/registry.go +++ b/pkg/teamloader/registry.go @@ -230,7 +230,7 @@ func createMCPTool(ctx context.Context, toolset latest.Toolset, _ string, runCon return nil, fmt.Errorf("fetching MCP server spec for %q: %w", mcpServerName, err) } - // TODO(dga): until the MCP Gateway supports oauth with cagent, we fetch the remote url and directly connect to it. + // TODO(dga): until the MCP Gateway supports oauth with docker agent, we fetch the remote url and directly connect to it. if serverSpec.Type == "remote" { return mcp.NewRemoteToolset(toolset.Name, serverSpec.Remote.URL, serverSpec.Remote.TransportType, nil), nil } diff --git a/pkg/telemetry/types.go b/pkg/telemetry/types.go index 079ccd0e8..de8848364 100644 --- a/pkg/telemetry/types.go +++ b/pkg/telemetry/types.go @@ -256,7 +256,7 @@ type HTTPClient interface { Do(req *http.Request) (*http.Response, error) } -// Client provides simplified telemetry functionality for cagent +// Client provides simplified telemetry functionality for docker agent type Client struct { logger *telemetryLogger userUUID string diff --git a/pkg/toolinstall/registry.go b/pkg/toolinstall/registry.go index dd24aa2e4..54b67c8f2 100644 --- a/pkg/toolinstall/registry.go +++ b/pkg/toolinstall/registry.go @@ -126,7 +126,7 @@ func NewRegistry() *Registry { } // SharedRegistry returns a package-level Registry instance that is reused -// across all tool resolutions within a cagent session, avoiding repeated +// across all tool resolutions within a docker agent session, avoiding repeated // YAML parsing and HTTP fetches. func SharedRegistry() *Registry { sharedRegistryOnce.Do(func() { diff --git a/pkg/toolinstall/resolver.go b/pkg/toolinstall/resolver.go index 7281e1d5f..5587cb028 100644 --- a/pkg/toolinstall/resolver.go +++ b/pkg/toolinstall/resolver.go @@ -13,7 +13,7 @@ import ( ) // EnsureCommand makes sure a command binary is available. -// It checks PATH first, then the cagent tools directory, then +// It checks PATH first, then the docker agent tools directory, then // attempts to install from the aqua registry if auto-install is enabled. // // Returns the resolved command (may be the same string if found in PATH, diff --git a/pkg/tools/builtin/fetch_test.go b/pkg/tools/builtin/fetch_test.go index 4815f92ae..65200f1fb 100644 --- a/pkg/tools/builtin/fetch_test.go +++ b/pkg/tools/builtin/fetch_test.go @@ -164,7 +164,7 @@ func TestFetch_Call_NoURLs(t *testing.T) { func TestFetch_Markdown(t *testing.T) { url := runHTTPServer(t, func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/html") - fmt.Fprint(w, "

Hello cagent

") + fmt.Fprint(w, "

Hello docker agent

") }) tool := NewFetchTool() @@ -177,14 +177,14 @@ func TestFetch_Markdown(t *testing.T) { assert.Contains(t, result.Output, "Successfully fetched") assert.Contains(t, result.Output, "Status: 200") - assert.Contains(t, result.Output, "Length: 14 bytes") - assert.Contains(t, result.Output, "# Hello cagent") + assert.Contains(t, result.Output, "Length: 20 bytes") + assert.Contains(t, result.Output, "# Hello docker agent") } func TestFetch_Text(t *testing.T) { url := runHTTPServer(t, func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/html") - fmt.Fprint(w, "

Hello cagent

") + fmt.Fprint(w, "

Hello docker agent

") }) tool := NewFetchTool() @@ -197,8 +197,8 @@ func TestFetch_Text(t *testing.T) { assert.Contains(t, result.Output, "Successfully fetched") assert.Contains(t, result.Output, "Status: 200") - assert.Contains(t, result.Output, "Length: 12 bytes") - assert.Contains(t, result.Output, "Hello cagent") + assert.Contains(t, result.Output, "Length: 18 bytes") + assert.Contains(t, result.Output, "Hello docker agent") } func runHTTPServer(t *testing.T, handler http.HandlerFunc) string { diff --git a/pkg/tools/mcp/mcp.go b/pkg/tools/mcp/mcp.go index f92280159..95cdb4256 100644 --- a/pkg/tools/mcp/mcp.go +++ b/pkg/tools/mcp/mcp.go @@ -203,7 +203,7 @@ func (ts *Toolset) doStart(ctx context.Context) error { initRequest := &mcp.InitializeRequest{ Params: &mcp.InitializeParams{ ClientInfo: &mcp.Implementation{ - Name: "cagent", + Name: "docker agent", Version: "1.0.0", }, Capabilities: &mcp.ClientCapabilities{ diff --git a/pkg/tools/mcp/remote.go b/pkg/tools/mcp/remote.go index d2ddb618f..69dac0d9c 100644 --- a/pkg/tools/mcp/remote.go +++ b/pkg/tools/mcp/remote.go @@ -59,7 +59,7 @@ func (c *remoteMCPClient) Initialize(ctx context.Context, _ *gomcp.InitializeReq // Create an MCP client with elicitation support impl := &gomcp.Implementation{ - Name: "cagent", + Name: "docker agent", Version: "1.0.0", } diff --git a/pkg/tools/mcp/stdio.go b/pkg/tools/mcp/stdio.go index 53a804061..1f9d7f4e4 100644 --- a/pkg/tools/mcp/stdio.go +++ b/pkg/tools/mcp/stdio.go @@ -45,7 +45,7 @@ func (c *stdioMCPClient) Initialize(ctx context.Context, _ *gomcp.InitializeRequ } client := gomcp.NewClient(&gomcp.Implementation{ - Name: "cagent", + Name: "docker agent", Version: "1.0.0", }, opts) diff --git a/pkg/tui/commands/commands.go b/pkg/tui/commands/commands.go index 47e33f1f5..9a9757ee4 100644 --- a/pkg/tui/commands/commands.go +++ b/pkg/tui/commands/commands.go @@ -253,7 +253,7 @@ func builtInFeedbackCommands() []Item { { ID: "feedback.feedback", Label: "Give Feedback", - Description: "Provide feedback about cagent", + Description: "Provide feedback about docker agent", Category: "Feedback", Execute: func(string) tea.Cmd { return core.CmdHandler(messages.OpenURLMsg{URL: feedback.Link}) diff --git a/pkg/tui/components/statusbar/statusbar.go b/pkg/tui/components/statusbar/statusbar.go index c25e4b4d4..bc57fe732 100644 --- a/pkg/tui/components/statusbar/statusbar.go +++ b/pkg/tui/components/statusbar/statusbar.go @@ -79,7 +79,7 @@ func (s *StatusBar) rebuild() { // Build the styled right side: optional new-tab button + version. var right string var rightW, newTabW int - ver := styles.MutedStyle.Render("cagent " + version.Version) + ver := styles.MutedStyle.Render("docker agent " + version.Version) if s.showNewTab { newTab := styles.MutedStyle.Render(" \u2502 ") + styles.HighlightWhiteStyle.Render("+") + @@ -134,7 +134,7 @@ func (s *StatusBar) rebuild() { // View renders the status bar. // -// Layout: [ help text ... (+ new tab) cagent VERSION ] +// Layout: [ help text ... (+ new tab) docker agent VERSION ] func (s *StatusBar) View() string { if s.cacheDirty { s.rebuild() diff --git a/pkg/tui/dialog/theme_picker.go b/pkg/tui/dialog/theme_picker.go index 61ecbe490..5584ee294 100644 --- a/pkg/tui/dialog/theme_picker.go +++ b/pkg/tui/dialog/theme_picker.go @@ -24,7 +24,7 @@ type ThemeChoice struct { Name string // Display name IsCurrent bool // Currently active theme IsDefault bool // Built-in default theme ("default") - IsBuiltin bool // Built-in theme shipped with cagent + IsBuiltin bool // Built-in theme shipped with docker agent } // themePickerDialog is a dialog for selecting a theme. diff --git a/pkg/tui/handlers.go b/pkg/tui/handlers.go index 747d4b299..84267d49b 100644 --- a/pkg/tui/handlers.go +++ b/pkg/tui/handlers.go @@ -614,18 +614,18 @@ func (m *appModel) startShell() (tea.Model, tea.Cmd) { if goruntime.GOOS == "windows" { if path, err := exec.LookPath("pwsh.exe"); err == nil { cmd = exec.Command(path, "-NoLogo", "-NoExit", "-Command", - `Write-Host ""; Write-Host "Type 'exit' to return to cagent 🐳"`) + `Write-Host ""; Write-Host "Type 'exit' to return to docker agent 🐳"`) } else if path, err := exec.LookPath("powershell.exe"); err == nil { cmd = exec.Command(path, "-NoLogo", "-NoExit", "-Command", - `Write-Host ""; Write-Host "Type 'exit' to return to cagent 🐳"`) + `Write-Host ""; Write-Host "Type 'exit' to return to docker agent 🐳"`) } else { shell := cmp.Or(os.Getenv("ComSpec"), "cmd.exe") - cmd = exec.Command(shell, "/K", `echo. & echo Type 'exit' to return to cagent`) + cmd = exec.Command(shell, "/K", `echo. & echo Type 'exit' to return to docker agent`) } } else { shell := cmp.Or(os.Getenv("SHELL"), "/bin/sh") cmd = exec.Command(shell, "-i", "-c", - `echo -e "\nType 'exit' to return to cagent 🐳"; exec `+shell) + `echo -e "\nType 'exit' to return to docker agent 🐳"; exec `+shell) } cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout diff --git a/pkg/tui/tui.go b/pkg/tui/tui.go index c7d65dd11..a5b51c9ce 100644 --- a/pkg/tui/tui.go +++ b/pkg/tui/tui.go @@ -2004,9 +2004,9 @@ func (m *appModel) View() tea.View { // When the agent is working, a rotating spinner character is prepended so that // terminal multiplexers (tmux) can detect activity in the pane. func (m *appModel) windowTitle() string { - title := "cagent" + title := "docker agent" if sessionTitle := m.sessionState.SessionTitle(); sessionTitle != "" { - title = sessionTitle + " - cagent" + title = sessionTitle + " - docker agent" } if m.chatPage.IsWorking() { title = spinner.Frame(m.animFrame) + " " + title diff --git a/pkg/userconfig/userconfig.go b/pkg/userconfig/userconfig.go index 6e8910942..7f93e3830 100644 --- a/pkg/userconfig/userconfig.go +++ b/pkg/userconfig/userconfig.go @@ -1,4 +1,4 @@ -// Package userconfig provides user-level configuration for cagent. +// Package userconfig provides user-level configuration for docker agent. // This configuration is stored in ~/.config/cagent/config.yaml and contains // user preferences like aliases. package userconfig @@ -88,7 +88,7 @@ type CredentialHelper struct { // CurrentVersion is the current version of the user config format const CurrentVersion = "v1" -// Config represents the user-level cagent configuration +// Config represents the user-level docker agent configuration type Config struct { // mu protects concurrent access to the Aliases map. // Config methods may be called from parallel tests or goroutines.