- Updated ImageRegistry to use public Docker Hub (anthonyrawlins namespace) - Modified image naming: chorus-base, chorus-rust-dev, chorus-go-dev, etc. - Added Docker Hub URLs and actual image sizes to metadata - Created comprehensive TaskExecutionEngine.md documentation covering: * Complete architecture and implementation details * Security isolation layers and threat mitigation * Performance characteristics and benchmarks * Real-world examples with resource usage metrics * Troubleshooting guide and FAQ * Comparisons with alternative approaches (SSH, VMs, native) Images now publicly available at docker.io/anthonyrawlins/chorus-* 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
263 lines
8.1 KiB
Go
263 lines
8.1 KiB
Go
package execution
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
// ImageRegistry is the default registry for CHORUS development images
|
|
ImageRegistry = "anthonyrawlins"
|
|
|
|
// ImageVersion is the default version tag to use
|
|
ImageVersion = "latest"
|
|
)
|
|
|
|
// ImageSelector maps task languages and contexts to appropriate development images
|
|
type ImageSelector struct {
|
|
registry string
|
|
version string
|
|
}
|
|
|
|
// NewImageSelector creates a new image selector with default settings
|
|
func NewImageSelector() *ImageSelector {
|
|
return &ImageSelector{
|
|
registry: ImageRegistry,
|
|
version: ImageVersion,
|
|
}
|
|
}
|
|
|
|
// NewImageSelectorWithConfig creates an image selector with custom registry and version
|
|
func NewImageSelectorWithConfig(registry, version string) *ImageSelector {
|
|
if registry == "" {
|
|
registry = ImageRegistry
|
|
}
|
|
if version == "" {
|
|
version = ImageVersion
|
|
}
|
|
return &ImageSelector{
|
|
registry: registry,
|
|
version: version,
|
|
}
|
|
}
|
|
|
|
// SelectImage returns the appropriate image name for a given language
|
|
func (s *ImageSelector) SelectImage(language string) string {
|
|
imageMap := map[string]string{
|
|
"rust": "chorus-rust-dev",
|
|
"go": "chorus-go-dev",
|
|
"golang": "chorus-go-dev",
|
|
"python": "chorus-python-dev",
|
|
"py": "chorus-python-dev",
|
|
"javascript": "chorus-node-dev",
|
|
"js": "chorus-node-dev",
|
|
"typescript": "chorus-node-dev",
|
|
"ts": "chorus-node-dev",
|
|
"node": "chorus-node-dev",
|
|
"nodejs": "chorus-node-dev",
|
|
"java": "chorus-java-dev",
|
|
"cpp": "chorus-cpp-dev",
|
|
"c++": "chorus-cpp-dev",
|
|
"c": "chorus-cpp-dev",
|
|
}
|
|
|
|
normalizedLang := strings.ToLower(strings.TrimSpace(language))
|
|
|
|
if img, ok := imageMap[normalizedLang]; ok {
|
|
return fmt.Sprintf("%s/%s:%s", s.registry, img, s.version)
|
|
}
|
|
|
|
// Default to base image if language not recognized
|
|
return fmt.Sprintf("%s/chorus-base:%s", s.registry, s.version)
|
|
}
|
|
|
|
// DetectLanguage analyzes task context to determine primary programming language
|
|
func (s *ImageSelector) DetectLanguage(task *TaskExecutionRequest) string {
|
|
// Priority 1: Explicit language specification
|
|
if lang, ok := task.Context["language"].(string); ok && lang != "" {
|
|
return strings.ToLower(strings.TrimSpace(lang))
|
|
}
|
|
|
|
// Priority 2: Language hint in requirements
|
|
if task.Requirements != nil && task.Requirements.AIModel != "" {
|
|
// Some models might hint at language in their name
|
|
modelLang := extractLanguageFromModel(task.Requirements.AIModel)
|
|
if modelLang != "" {
|
|
return modelLang
|
|
}
|
|
}
|
|
|
|
// Priority 3: Repository URL analysis
|
|
if repoURL, ok := task.Context["repository_url"].(string); ok && repoURL != "" {
|
|
return detectLanguageFromRepo(repoURL)
|
|
}
|
|
|
|
// Priority 4: Description keyword analysis
|
|
return detectLanguageFromDescription(task.Description)
|
|
}
|
|
|
|
// SelectImageForTask is a convenience method that detects language and returns appropriate image
|
|
func (s *ImageSelector) SelectImageForTask(task *TaskExecutionRequest) string {
|
|
language := s.DetectLanguage(task)
|
|
return s.SelectImage(language)
|
|
}
|
|
|
|
// detectLanguageFromDescription analyzes task description for language keywords
|
|
func detectLanguageFromDescription(description string) string {
|
|
desc := strings.ToLower(description)
|
|
|
|
// Keyword map with priority (specific keywords beat generic ones)
|
|
keywords := []struct {
|
|
language string
|
|
patterns []string
|
|
priority int
|
|
}{
|
|
// High priority - specific language indicators
|
|
{"rust", []string{"rust", "cargo.toml", ".rs file", "rustc", "cargo build"}, 3},
|
|
{"go", []string{"golang", "go.mod", "go.sum", ".go file", "go build"}, 3},
|
|
{"python", []string{"python3", "pip install", ".py file", "pytest", "requirements.txt", "pyproject.toml"}, 3},
|
|
{"typescript", []string{"typescript", ".ts file", "tsconfig.json"}, 3},
|
|
{"javascript", []string{"node.js", "npm install", "package.json", ".js file"}, 2},
|
|
{"java", []string{"java", "maven", "gradle", "pom.xml", ".java file"}, 3},
|
|
{"cpp", []string{"c++", "cmake", ".cpp file", ".cc file", "makefile"}, 3},
|
|
|
|
// Medium priority - generic mentions
|
|
{"rust", []string{"rust"}, 2},
|
|
{"go", []string{"go "}, 2},
|
|
{"python", []string{"python"}, 2},
|
|
{"node", []string{"node ", "npm ", "yarn "}, 2},
|
|
{"java", []string{"java "}, 2},
|
|
{"cpp", []string{"c++ ", "cpp "}, 2},
|
|
{"c", []string{" c "}, 1},
|
|
}
|
|
|
|
bestMatch := ""
|
|
bestPriority := 0
|
|
|
|
for _, kw := range keywords {
|
|
for _, pattern := range kw.patterns {
|
|
if strings.Contains(desc, pattern) {
|
|
if kw.priority > bestPriority {
|
|
bestMatch = kw.language
|
|
bestPriority = kw.priority
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if bestMatch != "" {
|
|
return bestMatch
|
|
}
|
|
|
|
return "base"
|
|
}
|
|
|
|
// detectLanguageFromRepo attempts to detect language from repository URL or name
|
|
func detectLanguageFromRepo(repoURL string) string {
|
|
repo := strings.ToLower(repoURL)
|
|
|
|
// Check for language-specific repository naming patterns
|
|
patterns := map[string][]string{
|
|
"rust": {"-rs", ".rs", "rust-"},
|
|
"go": {"-go", ".go", "go-"},
|
|
"python": {"-py", ".py", "python-"},
|
|
"javascript": {"-js", ".js", "node-"},
|
|
"typescript": {"-ts", ".ts"},
|
|
"java": {"-java", ".java"},
|
|
"cpp": {"-cpp", ".cpp", "-cxx"},
|
|
}
|
|
|
|
for lang, pats := range patterns {
|
|
for _, pat := range pats {
|
|
if strings.Contains(repo, pat) {
|
|
return lang
|
|
}
|
|
}
|
|
}
|
|
|
|
return "base"
|
|
}
|
|
|
|
// extractLanguageFromModel tries to extract language hints from model name
|
|
func extractLanguageFromModel(modelName string) string {
|
|
model := strings.ToLower(modelName)
|
|
|
|
// Some models are language-specific
|
|
if strings.Contains(model, "codellama") {
|
|
return "base" // CodeLlama is multi-language
|
|
}
|
|
if strings.Contains(model, "go") && strings.Contains(model, "coder") {
|
|
return "go"
|
|
}
|
|
if strings.Contains(model, "rust") {
|
|
return "rust"
|
|
}
|
|
if strings.Contains(model, "python") {
|
|
return "python"
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
// GetAvailableImages returns a list of all available development images
|
|
func (s *ImageSelector) GetAvailableImages() []string {
|
|
images := []string{"chorus-base", "chorus-rust-dev", "chorus-go-dev", "chorus-python-dev", "chorus-node-dev", "chorus-java-dev", "chorus-cpp-dev"}
|
|
result := make([]string, len(images))
|
|
|
|
for i, img := range images {
|
|
result[i] = fmt.Sprintf("%s/%s:%s", s.registry, img, s.version)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// GetImageInfo returns metadata about a specific image
|
|
func (s *ImageSelector) GetImageInfo(imageName string) map[string]string {
|
|
infoMap := map[string]map[string]string{
|
|
"chorus-base": {
|
|
"description": "Base Debian development environment with common tools",
|
|
"size": "~643MB",
|
|
"tools": "git, curl, build-essential, vim, jq",
|
|
"registry": "docker.io/anthonyrawlins/chorus-base",
|
|
},
|
|
"chorus-rust-dev": {
|
|
"description": "Rust development environment with cargo and tooling",
|
|
"size": "~2.42GB",
|
|
"tools": "rustc, cargo, clippy, rustfmt, ripgrep, fd-find",
|
|
"registry": "docker.io/anthonyrawlins/chorus-rust-dev",
|
|
},
|
|
"chorus-go-dev": {
|
|
"description": "Go development environment with standard tooling",
|
|
"size": "~1GB",
|
|
"tools": "go1.22, gopls, delve, staticcheck, golangci-lint",
|
|
"registry": "docker.io/anthonyrawlins/chorus-go-dev",
|
|
},
|
|
"chorus-python-dev": {
|
|
"description": "Python development environment with modern tooling",
|
|
"size": "~1.07GB",
|
|
"tools": "python3.11, uv, ruff, black, pytest, mypy",
|
|
"registry": "docker.io/anthonyrawlins/chorus-python-dev",
|
|
},
|
|
"chorus-node-dev": {
|
|
"description": "Node.js development environment with package managers",
|
|
"size": "~982MB",
|
|
"tools": "node20, pnpm, yarn, typescript, eslint, prettier",
|
|
"registry": "docker.io/anthonyrawlins/chorus-node-dev",
|
|
},
|
|
"chorus-java-dev": {
|
|
"description": "Java development environment with build tools",
|
|
"size": "~1.3GB",
|
|
"tools": "openjdk-17, maven, gradle",
|
|
"registry": "docker.io/anthonyrawlins/chorus-java-dev",
|
|
},
|
|
"chorus-cpp-dev": {
|
|
"description": "C/C++ development environment with compilers and tools",
|
|
"size": "~1.63GB",
|
|
"tools": "gcc, g++, clang, cmake, ninja, gdb, valgrind",
|
|
"registry": "docker.io/anthonyrawlins/chorus-cpp-dev",
|
|
},
|
|
}
|
|
|
|
return infoMap[imageName]
|
|
} |