diff --git a/.github/aw/create-shared-agentic-workflow.md b/.github/aw/create-shared-agentic-workflow.md index 56dded0059..a971510441 100644 --- a/.github/aw/create-shared-agentic-workflow.md +++ b/.github/aw/create-shared-agentic-workflow.md @@ -93,7 +93,7 @@ mcp-servers: \`\`\`yaml mcp-servers: serena: - container: "ghcr.io/oraios/serena" + container: "ghcr.io/githubnext/serena-mcp-server" version: "latest" args: # args come before the docker image argument - "-v" diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml index 99c8e85cd2..217fcb9cc5 100644 --- a/.github/workflows/archie.lock.yml +++ b/.github/workflows/archie.lock.yml @@ -420,7 +420,7 @@ jobs: }, "serena": { "type": "stdio", - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": ["--network", "host"], "entrypoint": "serena", "entrypointArgs": ["start-mcp-server", "--context", "codex", "--project", "${{ github.workspace }}"], diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index 69970b2505..d85d59ef4a 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -550,7 +550,7 @@ jobs: } }, "serena": { - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": [ "--network", "host" diff --git a/.github/workflows/daily-compiler-quality.lock.yml b/.github/workflows/daily-compiler-quality.lock.yml index e8559a41b4..25a435cc57 100644 --- a/.github/workflows/daily-compiler-quality.lock.yml +++ b/.github/workflows/daily-compiler-quality.lock.yml @@ -409,7 +409,7 @@ jobs: }, "serena": { "type": "stdio", - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": ["--network", "host"], "entrypoint": "serena", "entrypointArgs": ["start-mcp-server", "--context", "codex", "--project", "${{ github.workspace }}"], diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml index 81b476f551..1372125a7d 100644 --- a/.github/workflows/daily-file-diet.lock.yml +++ b/.github/workflows/daily-file-diet.lock.yml @@ -422,7 +422,7 @@ jobs: }, "serena": { "type": "stdio", - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": ["--network", "host"], "entrypoint": "serena", "entrypointArgs": ["start-mcp-server", "--context", "codex", "--project", "${{ github.workspace }}"], diff --git a/.github/workflows/daily-testify-uber-super-expert.lock.yml b/.github/workflows/daily-testify-uber-super-expert.lock.yml index 8eec5764a5..044a4e972f 100644 --- a/.github/workflows/daily-testify-uber-super-expert.lock.yml +++ b/.github/workflows/daily-testify-uber-super-expert.lock.yml @@ -432,7 +432,7 @@ jobs: }, "serena": { "type": "stdio", - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": ["--network", "host"], "entrypoint": "serena", "entrypointArgs": ["start-mcp-server", "--context", "codex", "--project", "${{ github.workspace }}"], diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index 0d2ce24611..f135d5c154 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -463,7 +463,7 @@ jobs: } }, "serena": { - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": [ "--network", "host" diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml index d30ba20dfd..7724b1ecbf 100644 --- a/.github/workflows/duplicate-code-detector.lock.yml +++ b/.github/workflows/duplicate-code-detector.lock.yml @@ -396,7 +396,7 @@ jobs: env_vars = ["GH_AW_MCP_LOG_DIR", "GH_AW_SAFE_OUTPUTS", "GH_AW_SAFE_OUTPUTS_CONFIG_PATH", "GH_AW_SAFE_OUTPUTS_TOOLS_PATH", "GH_AW_ASSETS_BRANCH", "GH_AW_ASSETS_MAX_SIZE_KB", "GH_AW_ASSETS_ALLOWED_EXTS", "GITHUB_REPOSITORY", "GITHUB_SERVER_URL", "GITHUB_SHA", "GITHUB_WORKSPACE", "DEFAULT_BRANCH"] [mcp_servers.serena] - container = "ghcr.io/oraios/serena:latest" + container = "ghcr.io/githubnext/serena-mcp-server:latest" args = [ "--network", "host", @@ -446,7 +446,7 @@ jobs: } }, "serena": { - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": [ "--network", "host" diff --git a/.github/workflows/glossary-maintainer.lock.yml b/.github/workflows/glossary-maintainer.lock.yml index e5aa1b7e1d..f2979df4cd 100644 --- a/.github/workflows/glossary-maintainer.lock.yml +++ b/.github/workflows/glossary-maintainer.lock.yml @@ -420,7 +420,7 @@ jobs: }, "serena": { "type": "stdio", - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": ["--network", "host"], "entrypoint": "serena", "entrypointArgs": ["start-mcp-server", "--context", "codex", "--project", "${{ github.workspace }}"], diff --git a/.github/workflows/go-fan.lock.yml b/.github/workflows/go-fan.lock.yml index 687954d30a..a31021bf22 100644 --- a/.github/workflows/go-fan.lock.yml +++ b/.github/workflows/go-fan.lock.yml @@ -399,7 +399,7 @@ jobs: } }, "serena": { - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": [ "--network", "host" diff --git a/.github/workflows/jsweep.lock.yml b/.github/workflows/jsweep.lock.yml index e5376b618b..e6554e9f1f 100644 --- a/.github/workflows/jsweep.lock.yml +++ b/.github/workflows/jsweep.lock.yml @@ -425,7 +425,7 @@ jobs: }, "serena": { "type": "stdio", - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": ["--network", "host"], "entrypoint": "serena", "entrypointArgs": ["start-mcp-server", "--context", "codex", "--project", "${{ github.workspace }}"], diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index b7c0fc0d80..71b3b87e1e 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -723,7 +723,7 @@ jobs: }, "serena": { "type": "stdio", - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": ["--network", "host"], "entrypoint": "serena", "entrypointArgs": ["start-mcp-server", "--context", "codex", "--project", "${{ github.workspace }}"], diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index 5fc54f25c4..bd0e3b70eb 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -538,7 +538,7 @@ jobs: }, "serena": { "type": "stdio", - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": ["--network", "host"], "entrypoint": "serena", "entrypointArgs": ["start-mcp-server", "--context", "codex", "--project", "${{ github.workspace }}"], diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml index 5869e28a72..6d5d89f53e 100644 --- a/.github/workflows/repository-quality-improver.lock.yml +++ b/.github/workflows/repository-quality-improver.lock.yml @@ -411,7 +411,7 @@ jobs: }, "serena": { "type": "stdio", - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": ["--network", "host"], "entrypoint": "serena", "entrypointArgs": ["start-mcp-server", "--context", "codex", "--project", "${{ github.workspace }}"], diff --git a/.github/workflows/sergo.lock.yml b/.github/workflows/sergo.lock.yml index 4036302fbe..4bf097d5b7 100644 --- a/.github/workflows/sergo.lock.yml +++ b/.github/workflows/sergo.lock.yml @@ -400,7 +400,7 @@ jobs: } }, "serena": { - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": [ "--network", "host" diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index 88052ef4d6..8e4d3a4b69 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -648,7 +648,7 @@ jobs: } }, "serena": { - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": [ "--network", "host" diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index 9a763606c6..617dab44cb 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -664,7 +664,7 @@ jobs: env_vars = ["GH_AW_MCP_LOG_DIR", "GH_AW_SAFE_OUTPUTS", "GH_AW_SAFE_OUTPUTS_CONFIG_PATH", "GH_AW_SAFE_OUTPUTS_TOOLS_PATH", "GH_AW_ASSETS_BRANCH", "GH_AW_ASSETS_MAX_SIZE_KB", "GH_AW_ASSETS_ALLOWED_EXTS", "GITHUB_REPOSITORY", "GITHUB_SERVER_URL", "GITHUB_SHA", "GITHUB_WORKSPACE", "DEFAULT_BRANCH"] [mcp_servers.serena] - container = "ghcr.io/oraios/serena:latest" + container = "ghcr.io/githubnext/serena-mcp-server:latest" args = [ "--network", "host", @@ -742,7 +742,7 @@ jobs: } }, "serena": { - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": [ "--network", "host" diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index ea3e9d0a3b..d51ba54afb 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -556,7 +556,7 @@ jobs: }, "serena": { "type": "stdio", - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": ["--network", "host"], "entrypoint": "serena", "entrypointArgs": ["start-mcp-server", "--context", "codex", "--project", "${{ github.workspace }}"], diff --git a/.github/workflows/terminal-stylist.lock.yml b/.github/workflows/terminal-stylist.lock.yml index 5aa7373762..cf4e8720b7 100644 --- a/.github/workflows/terminal-stylist.lock.yml +++ b/.github/workflows/terminal-stylist.lock.yml @@ -392,7 +392,7 @@ jobs: }, "serena": { "type": "stdio", - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": ["--network", "host"], "entrypoint": "serena", "entrypointArgs": ["start-mcp-server", "--context", "codex", "--project", "${{ github.workspace }}"], diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml index b31aac7324..6f7e6186c7 100644 --- a/.github/workflows/typist.lock.yml +++ b/.github/workflows/typist.lock.yml @@ -387,7 +387,7 @@ jobs: } }, "serena": { - "container": "ghcr.io/oraios/serena:latest", + "container": "ghcr.io/githubnext/serena-mcp-server:latest", "args": [ "--network", "host" diff --git a/pkg/cli/templates/create-shared-agentic-workflow.agent.md b/pkg/cli/templates/create-shared-agentic-workflow.agent.md index 56dded0059..a971510441 100644 --- a/pkg/cli/templates/create-shared-agentic-workflow.agent.md +++ b/pkg/cli/templates/create-shared-agentic-workflow.agent.md @@ -93,7 +93,7 @@ mcp-servers: \`\`\`yaml mcp-servers: serena: - container: "ghcr.io/oraios/serena" + container: "ghcr.io/githubnext/serena-mcp-server" version: "latest" args: # args come before the docker image argument - "-v" diff --git a/pkg/cli/templates/create-shared-agentic-workflow.md b/pkg/cli/templates/create-shared-agentic-workflow.md index 56dded0059..a971510441 100644 --- a/pkg/cli/templates/create-shared-agentic-workflow.md +++ b/pkg/cli/templates/create-shared-agentic-workflow.md @@ -93,7 +93,7 @@ mcp-servers: \`\`\`yaml mcp-servers: serena: - container: "ghcr.io/oraios/serena" + container: "ghcr.io/githubnext/serena-mcp-server" version: "latest" args: # args come before the docker image argument - "-v" diff --git a/pkg/cli/templates/create-shared-agentic-workflow.prompt.md b/pkg/cli/templates/create-shared-agentic-workflow.prompt.md index 9a8886b021..c289285f15 100644 --- a/pkg/cli/templates/create-shared-agentic-workflow.prompt.md +++ b/pkg/cli/templates/create-shared-agentic-workflow.prompt.md @@ -92,7 +92,7 @@ mcp-servers: \`\`\`yaml mcp-servers: serena: - container: "ghcr.io/oraios/serena" + container: "ghcr.io/githubnext/serena-mcp-server" version: "latest" args: # args come before the docker image argument - "-v" diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 98900b839e..d00966c824 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -284,6 +284,30 @@ const DefaultMCPGatewayVersion Version = "v0.0.62" // DefaultMCPGatewayContainer is the default container image for the MCP Gateway const DefaultMCPGatewayContainer = "ghcr.io/githubnext/gh-aw-mcpg" +// DefaultSerenaMCPServerContainer is the default container image for the Serena MCP server +const DefaultSerenaMCPServerContainer = "ghcr.io/githubnext/serena-mcp-server" + +// OraiosSerenaContainer is the Oraios Serena MCP server container image (legacy) +const OraiosSerenaContainer = "ghcr.io/oraios/serena" + +// SerenaLanguageSupport defines the supported languages for each Serena container image +var SerenaLanguageSupport = map[string][]string{ + DefaultSerenaMCPServerContainer: { + "go", "typescript", "javascript", "python", "java", "rust", "csharp", + "cpp", "c", "ruby", "php", "bash", "swift", "kotlin", "scala", + "haskell", "elixir", "erlang", "clojure", "lua", "perl", "r", + "dart", "julia", "fortran", "nix", "rego", "terraform", "yaml", + "markdown", "zig", "elm", + }, + OraiosSerenaContainer: { + "go", "typescript", "javascript", "python", "java", "rust", "csharp", + "cpp", "c", "ruby", "php", "bash", "swift", "kotlin", "scala", + "haskell", "elixir", "erlang", "clojure", "lua", "perl", "r", + "dart", "julia", "fortran", "nix", "rego", "terraform", "yaml", + "markdown", "zig", "elm", + }, +} + // DefaultSandboxRuntimeVersion is the default version of the @anthropic-ai/sandbox-runtime package (SRT) const DefaultSandboxRuntimeVersion Version = "0.0.28" diff --git a/pkg/workflow/importable_tools_test.go b/pkg/workflow/importable_tools_test.go index dd269b53a8..105b6086de 100644 --- a/pkg/workflow/importable_tools_test.go +++ b/pkg/workflow/importable_tools_test.go @@ -154,7 +154,7 @@ Uses imported serena tool. } // Verify serena container (now using Docker instead of uvx) - if !strings.Contains(workflowData, "ghcr.io/oraios/serena:latest") { + if !strings.Contains(workflowData, "ghcr.io/githubnext/serena-mcp-server:latest") { t.Error("Expected compiled workflow to contain serena Docker container") } @@ -319,7 +319,7 @@ Uses all imported tools. if !strings.Contains(workflowData, "mcr.microsoft.com/playwright/mcp") { t.Error("Expected compiled workflow to contain playwright Docker image") } - if !strings.Contains(workflowData, "ghcr.io/oraios/serena:latest") { + if !strings.Contains(workflowData, "ghcr.io/githubnext/serena-mcp-server:latest") { t.Error("Expected compiled workflow to contain serena Docker container") } if !strings.Contains(workflowData, "example.com") { @@ -403,7 +403,7 @@ Uses imported serena with language config. } // Verify serena container is present - if !strings.Contains(workflowData, "ghcr.io/oraios/serena") { + if !strings.Contains(workflowData, "ghcr.io/githubnext/serena-mcp-server") { t.Error("Expected serena to use Docker container") } } @@ -1013,7 +1013,7 @@ Uses imported serena in local mode. } // Verify NO container is used - if strings.Contains(workflowData, "ghcr.io/oraios/serena:latest") { + if strings.Contains(workflowData, "ghcr.io/githubnext/serena-mcp-server:latest") { t.Error("Did not expect serena local mode to use Docker container") } } diff --git a/pkg/workflow/mcp-config.go b/pkg/workflow/mcp-config.go index d2d617d4a0..32b6122f95 100644 --- a/pkg/workflow/mcp-config.go +++ b/pkg/workflow/mcp-config.go @@ -145,9 +145,95 @@ func renderPlaywrightMCPConfigWithOptions(yaml *strings.Builder, playwrightTool } } +// selectSerenaContainer determines which Serena container image to use based on requested languages +// Returns the container image path that supports all requested languages +func selectSerenaContainer(serenaTool any) string { + // Extract languages from the serena tool configuration + var requestedLanguages []string + + if toolMap, ok := serenaTool.(map[string]any); ok { + // Check for short syntax (array of language names) + if langs, ok := toolMap["langs"].([]any); ok { + for _, lang := range langs { + if langStr, ok := lang.(string); ok { + requestedLanguages = append(requestedLanguages, langStr) + } + } + } + + // Check for detailed language configuration + if langs, ok := toolMap["languages"].(map[string]any); ok { + for langName := range langs { + requestedLanguages = append(requestedLanguages, langName) + } + } + } + + // If we parsed serena from SerenaToolConfig + if serenaConfig, ok := serenaTool.(*SerenaToolConfig); ok { + requestedLanguages = append(requestedLanguages, serenaConfig.ShortSyntax...) + if serenaConfig.Languages != nil { + for langName := range serenaConfig.Languages { + requestedLanguages = append(requestedLanguages, langName) + } + } + } + + // If no languages specified, use default container + if len(requestedLanguages) == 0 { + return constants.DefaultSerenaMCPServerContainer + } + + // Check if all requested languages are supported by the default container + defaultSupported := true + for _, lang := range requestedLanguages { + supported := false + for _, supportedLang := range constants.SerenaLanguageSupport[constants.DefaultSerenaMCPServerContainer] { + if lang == supportedLang { + supported = true + break + } + } + if !supported { + defaultSupported = false + mcpLog.Printf("Language '%s' not found in default container support list", lang) + break + } + } + + if defaultSupported { + return constants.DefaultSerenaMCPServerContainer + } + + // Check if Oraios container supports the languages + oraiosSupported := true + for _, lang := range requestedLanguages { + supported := false + for _, supportedLang := range constants.SerenaLanguageSupport[constants.OraiosSerenaContainer] { + if lang == supportedLang { + supported = true + break + } + } + if !supported { + oraiosSupported = false + break + } + } + + if oraiosSupported { + mcpLog.Printf("Using Oraios Serena container as fallback for languages: %v", requestedLanguages) + return constants.OraiosSerenaContainer + } + + // Default to the new GitHub container if neither supports all languages + mcpLog.Printf("Using default Serena container (some languages may not be supported): %v", requestedLanguages) + return constants.DefaultSerenaMCPServerContainer +} + // renderSerenaMCPConfigWithOptions generates the Serena MCP server configuration with engine-specific options // Supports two modes: -// - "docker" (default): Uses Docker container with stdio transport (ghcr.io/oraios/serena:latest) +// - "docker" (default): Uses Docker container with stdio transport (ghcr.io/githubnext/serena-mcp-server:latest) // - "local": Uses local uvx with HTTP transport on fixed port func renderSerenaMCPConfigWithOptions(yaml *strings.Builder, serenaTool any, isLast bool, includeCopilotFields bool, inlineArgs bool) { customArgs := getSerenaCustomArgs(serenaTool) @@ -177,8 +263,9 @@ func renderSerenaMCPConfigWithOptions(yaml *strings.Builder, serenaTool any, isL yaml.WriteString(" \"type\": \"stdio\",\n") } - // Use Serena's Docker container image - yaml.WriteString(" \"container\": \"ghcr.io/oraios/serena:latest\",\n") + // Select the appropriate Serena container based on requested languages + containerImage := selectSerenaContainer(serenaTool) + yaml.WriteString(" \"container\": \"" + containerImage + ":latest\",\n") // Docker runtime args (--network host for network access) if inlineArgs { diff --git a/pkg/workflow/mcp_config_comprehensive_test.go b/pkg/workflow/mcp_config_comprehensive_test.go index 702b3f7f78..7d0439c244 100644 --- a/pkg/workflow/mcp_config_comprehensive_test.go +++ b/pkg/workflow/mcp_config_comprehensive_test.go @@ -574,7 +574,7 @@ func TestRenderSerenaMCPConfigWithOptions(t *testing.T) { inlineArgs: false, expectedContent: []string{ `"serena": {`, - `"container": "ghcr.io/oraios/serena:latest"`, + `"container": "ghcr.io/githubnext/serena-mcp-server:latest"`, `"entrypoint": "serena"`, `"entrypointArgs"`, `"start-mcp-server"`, @@ -593,7 +593,7 @@ func TestRenderSerenaMCPConfigWithOptions(t *testing.T) { inlineArgs: false, expectedContent: []string{ `"serena": {`, - `"container": "ghcr.io/oraios/serena:latest"`, + `"container": "ghcr.io/githubnext/serena-mcp-server:latest"`, ` }`, }, unexpectedContent: []string{ @@ -611,7 +611,7 @@ func TestRenderSerenaMCPConfigWithOptions(t *testing.T) { expectedContent: []string{ `"serena": {`, `"type": "stdio"`, - `"container": "ghcr.io/oraios/serena:latest"`, + `"container": "ghcr.io/githubnext/serena-mcp-server:latest"`, }, unexpectedContent: []string{}, }, @@ -624,7 +624,7 @@ func TestRenderSerenaMCPConfigWithOptions(t *testing.T) { expectedContent: []string{ `"serena": {`, `"type": "stdio"`, - `"container": "ghcr.io/oraios/serena:latest"`, + `"container": "ghcr.io/githubnext/serena-mcp-server:latest"`, `"entrypointArgs": ["start-mcp-server", "--context", "codex", "--project", "${{ github.workspace }}"]`, }, unexpectedContent: []string{}, @@ -639,7 +639,7 @@ func TestRenderSerenaMCPConfigWithOptions(t *testing.T) { inlineArgs: false, expectedContent: []string{ `"serena": {`, - `"container": "ghcr.io/oraios/serena:latest"`, + `"container": "ghcr.io/githubnext/serena-mcp-server:latest"`, `"--verbose"`, `"--debug"`, }, @@ -1161,7 +1161,7 @@ func TestRenderSerenaMCPConfigLocalMode(t *testing.T) { expectedContent: []string{ `"serena": {`, `"type": "stdio"`, - `"container": "ghcr.io/oraios/serena:latest"`, + `"container": "ghcr.io/githubnext/serena-mcp-server:latest"`, }, unexpectedContent: []string{ `"url"`, @@ -1181,7 +1181,7 @@ func TestRenderSerenaMCPConfigLocalMode(t *testing.T) { expectedContent: []string{ `"serena": {`, `"type": "stdio"`, - `"container": "ghcr.io/oraios/serena:latest"`, + `"container": "ghcr.io/githubnext/serena-mcp-server:latest"`, }, unexpectedContent: []string{ `"url"`, diff --git a/pkg/workflow/mcp_renderer.go b/pkg/workflow/mcp_renderer.go index 9206b028cf..d05c125f65 100644 --- a/pkg/workflow/mcp_renderer.go +++ b/pkg/workflow/mcp_renderer.go @@ -212,7 +212,9 @@ func (r *MCPConfigRendererUnified) renderSerenaTOML(yaml *strings.Builder, seren yaml.WriteString(" url = \"http://localhost:$GH_AW_SERENA_PORT\"\n") } else { // Docker mode: use stdio transport (default) - yaml.WriteString(" container = \"ghcr.io/oraios/serena:latest\"\n") + // Select the appropriate Serena container based on requested languages + containerImage := selectSerenaContainer(serenaTool) + yaml.WriteString(" container = \"" + containerImage + ":latest\"\n") // Docker runtime args (--network host for network access) yaml.WriteString(" args = [\n") diff --git a/pkg/workflow/serena_container_selection_test.go b/pkg/workflow/serena_container_selection_test.go new file mode 100644 index 0000000000..19a9feaf21 --- /dev/null +++ b/pkg/workflow/serena_container_selection_test.go @@ -0,0 +1,108 @@ +package workflow + +import ( + "testing" + + "github.com/githubnext/gh-aw/pkg/constants" +) + +func TestSelectSerenaContainer(t *testing.T) { + tests := []struct { + name string + serenaTool any + expectedContainer string + }{ + { + name: "no languages specified - uses default", + serenaTool: map[string]any{ + "mode": "docker", + }, + expectedContainer: constants.DefaultSerenaMCPServerContainer, + }, + { + name: "supported languages - uses default", + serenaTool: map[string]any{ + "langs": []any{"go", "typescript"}, + }, + expectedContainer: constants.DefaultSerenaMCPServerContainer, + }, + { + name: "all supported languages - uses default", + serenaTool: map[string]any{ + "languages": map[string]any{ + "go": map[string]any{}, + "typescript": map[string]any{}, + "python": map[string]any{}, + }, + }, + expectedContainer: constants.DefaultSerenaMCPServerContainer, + }, + { + name: "unsupported language - still uses default", + serenaTool: map[string]any{ + "langs": []any{"unsupported-lang"}, + }, + expectedContainer: constants.DefaultSerenaMCPServerContainer, + }, + { + name: "SerenaToolConfig with short syntax", + serenaTool: &SerenaToolConfig{ + ShortSyntax: []string{"go", "rust"}, + }, + expectedContainer: constants.DefaultSerenaMCPServerContainer, + }, + { + name: "SerenaToolConfig with detailed languages", + serenaTool: &SerenaToolConfig{ + Languages: map[string]*SerenaLangConfig{ + "python": {}, + "java": {}, + }, + }, + expectedContainer: constants.DefaultSerenaMCPServerContainer, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := selectSerenaContainer(tt.serenaTool) + if result != tt.expectedContainer { + t.Errorf("selectSerenaContainer() = %v, want %v", result, tt.expectedContainer) + } + }) + } +} + +func TestSerenaLanguageSupport(t *testing.T) { + // Test that the language support map is properly defined + if len(constants.SerenaLanguageSupport) == 0 { + t.Error("SerenaLanguageSupport map is empty") + } + + // Test that default container has languages defined + defaultLangs := constants.SerenaLanguageSupport[constants.DefaultSerenaMCPServerContainer] + if len(defaultLangs) == 0 { + t.Error("Default Serena container has no supported languages defined") + } + + // Test that Oraios container has languages defined + oraiosLangs := constants.SerenaLanguageSupport[constants.OraiosSerenaContainer] + if len(oraiosLangs) == 0 { + t.Error("Oraios Serena container has no supported languages defined") + } + + // Verify some expected languages are present in default container + expectedLangs := []string{"go", "typescript", "python", "java", "rust"} + for _, lang := range expectedLangs { + found := false + for _, supportedLang := range defaultLangs { + if supportedLang == lang { + found = true + break + } + } + if !found { + t.Errorf("Expected language '%s' not found in default container support list", lang) + } + } +}