root.go
1 package cli 2 3 import ( 4 "fmt" 5 "math/rand" 6 "os" 7 "sort" 8 "strings" 9 "time" 10 11 "github.com/spf13/cobra" 12 "github.com/TransformerOS/kamaji-go/internal/style" 13 ) 14 15 var rootCmd = &cobra.Command{ 16 Use: "kamaji", 17 Short: "š„ Kamaji - AI CLI Assistant", 18 Long: style.GetCompactBanner() + "\n" + style.Info("Kamaji AI CLI with multi-agent capabilities and tool integration"), 19 Run: func(cmd *cobra.Command, args []string) { 20 // If no subcommand specified, launch TUI by default 21 if err := runTUI(cmd, args); err != nil { 22 fmt.Fprintf(os.Stderr, "Error launching TUI: %v\n", err) 23 fmt.Fprintf(os.Stderr, "\nUse 'kamaji --help' to see all available commands.\n") 24 os.Exit(1) 25 } 26 }, 27 } 28 29 func showStyledHelp(cmd *cobra.Command) { 30 fmt.Printf("%s\n", style.Header("š„ Available Commands:")) 31 32 // Core commands 33 coreCommands := []struct { 34 name, desc string 35 }{ 36 {"ask", "Ask a single question to Kamaji"}, 37 {"chat", "Start interactive chat with memory"}, 38 {"rag", "Query documents using RAG"}, 39 {"interactive", "Agent mode with filesystem and shell tools"}, 40 {"tui", "Launch beautiful terminal interface"}, 41 } 42 43 fmt.Printf("\n%s\n", style.Fire("š„ Core Commands:")) 44 for _, cmd := range coreCommands { 45 fmt.Printf(" %s %s\n", style.Highlight(cmd.name), style.DimText(cmd.desc)) 46 } 47 48 // Management commands 49 mgmtCommands := []struct { 50 name, desc string 51 }{ 52 {"work", "Work on tasks - prompts, paths, or task list"}, 53 {"tasks", "Show current task list"}, 54 {"queue", "Add tasks to task queue"}, 55 {"do", "Select and execute a task"}, 56 {"agents", "Manage AI agents and their capabilities"}, 57 {"tools", "Explore and manage available tools"}, 58 {"mcp", "Model Context Protocol server management"}, 59 {"workflow", "Automated workflow management"}, 60 } 61 62 fmt.Printf("\n%s\n", style.Warning("š¤ Management Commands:")) 63 for _, cmd := range mgmtCommands { 64 fmt.Printf(" %s %s\n", style.Highlight(cmd.name), style.DimText(cmd.desc)) 65 } 66 67 // Advanced commands 68 advancedCommands := []struct { 69 name, desc string 70 }{ 71 {"genetic", "Genetic algorithm optimization"}, 72 } 73 74 fmt.Printf("\n%s\n", style.Info("ā” Advanced Commands:")) 75 for _, cmd := range advancedCommands { 76 fmt.Printf(" %s %s\n", style.Highlight(cmd.name), style.DimText(cmd.desc)) 77 } 78 79 // Utility commands 80 utilCommands := []struct{ 81 name, desc string 82 }{ 83 {"update", "Update Kamaji to latest version"}, 84 {"config", "Manage Kamaji configuration"}, 85 {"version", "Show version information"}, 86 {"help", "Help about any command"}, 87 } 88 89 fmt.Printf("\n%s\n", style.Info("š ļø Utility Commands:")) 90 for _, cmd := range utilCommands { 91 fmt.Printf(" %s %s\n", style.Highlight(cmd.name), style.DimText(cmd.desc)) 92 } 93 94 fmt.Printf("\n%s\n", style.DimText("Use 'kamaji [command] --help' for more information about a command.")) 95 fmt.Printf("%s\n\n", style.Fire("š„ Ready to assist!")) 96 } 97 98 var geneticCmd = &cobra.Command{ 99 Use: "genetic", 100 Short: "Genetic algorithm optimization", 101 Long: "Use genetic algorithms to evolve and optimize code", 102 } 103 104 var evolveCmd = &cobra.Command{ 105 Use: "evolve [file]", 106 Short: "Evolve code using genetic algorithm", 107 Args: cobra.ExactArgs(1), 108 RunE: runEvolve, 109 } 110 111 type Individual struct { 112 Code string 113 Fitness float64 114 } 115 116 type Population []Individual 117 118 func Execute() error { 119 return rootCmd.Execute() 120 } 121 122 func init() { 123 rand.Seed(time.Now().UnixNano()) 124 125 // Core commands 126 rootCmd.AddCommand(askCmd) 127 rootCmd.AddCommand(chatCmd) 128 rootCmd.AddCommand(ragCmd) 129 rootCmd.AddCommand(interactiveCmd) 130 rootCmd.AddCommand(tuiCmd) 131 rootCmd.AddCommand(updateCmd) 132 rootCmd.AddCommand(configCmd) 133 rootCmd.AddCommand(versionCmd) 134 rootCmd.AddCommand(rebuildCmd) 135 136 // Management commands 137 rootCmd.AddCommand(workCmd) 138 rootCmd.AddCommand(tasksCmd) 139 rootCmd.AddCommand(queueCmd) 140 rootCmd.AddCommand(doCmd) 141 rootCmd.AddCommand(agentsCmd) 142 rootCmd.AddCommand(toolsCmd) 143 rootCmd.AddCommand(mcpCmd) 144 rootCmd.AddCommand(workflowCmd) 145 146 // Specialized commands 147 rootCmd.AddCommand(geneticCmd) 148 rootCmd.AddCommand(kamajiCmd) 149 150 geneticCmd.AddCommand(evolveCmd) 151 evolveCmd.Flags().IntP("population", "p", 20, "Population size") 152 evolveCmd.Flags().IntP("generations", "g", 50, "Maximum generations") 153 evolveCmd.Flags().Float64P("mutation", "m", 0.1, "Mutation rate") 154 evolveCmd.Flags().Float64P("crossover", "c", 0.7, "Crossover rate") 155 156 // Custom help command 157 helpCmd := &cobra.Command{ 158 Use: "help [command]", 159 Short: "Help about any command", 160 Run: func(cmd *cobra.Command, args []string) { 161 if len(args) == 0 { 162 fmt.Print(style.GetCompactBanner()) 163 showStyledHelp(rootCmd) 164 } else { 165 // Show help for specific command 166 if targetCmd, _, err := rootCmd.Find(args); err == nil { 167 targetCmd.Help() 168 } else { 169 fmt.Printf("%s\n", style.Error("Command not found: "+args[0])) 170 } 171 } 172 }, 173 } 174 rootCmd.AddCommand(helpCmd) 175 } 176 177 func runEvolve(cmd *cobra.Command, args []string) error { 178 filePath := args[0] 179 180 code, err := os.ReadFile(filePath) 181 if err != nil { 182 return fmt.Errorf("failed to read file: %w", err) 183 } 184 185 popSize, _ := cmd.Flags().GetInt("population") 186 generations, _ := cmd.Flags().GetInt("generations") 187 mutationRate, _ := cmd.Flags().GetFloat64("mutation") 188 crossoverRate, _ := cmd.Flags().GetFloat64("crossover") 189 190 fmt.Printf("𧬠REAL Genetic Algorithm Evolution\n") 191 fmt.Printf("Population: %d, Generations: %d\n", popSize, generations) 192 fmt.Printf("Mutation: %.2f, Crossover: %.2f\n", mutationRate, crossoverRate) 193 fmt.Printf("Original: %d chars\n\n", len(code)) 194 195 // Initialize population 196 population := initializePopulation(string(code), popSize) 197 198 for gen := 0; gen < generations; gen++ { 199 // Evaluate fitness 200 for i := range population { 201 population[i].Fitness = calculateFitness(population[i].Code) 202 } 203 204 // Sort by fitness (descending) 205 sort.Slice(population, func(i, j int) bool { 206 return population[i].Fitness > population[j].Fitness 207 }) 208 209 if gen%10 == 0 { 210 fmt.Printf("Gen %d: Best=%.4f, Worst=%.4f, Avg=%.4f\n", 211 gen, population[0].Fitness, population[len(population)-1].Fitness, avgFitness(population)) 212 } 213 214 // Create new generation 215 newPop := make(Population, popSize) 216 217 // Elitism - keep best 20% 218 eliteCount := popSize / 5 219 copy(newPop[:eliteCount], population[:eliteCount]) 220 221 // Generate offspring 222 for i := eliteCount; i < popSize; i++ { 223 parent1 := tournamentSelect(population) 224 parent2 := tournamentSelect(population) 225 226 var child Individual 227 if rand.Float64() < crossoverRate { 228 child = crossover(parent1, parent2) 229 } else { 230 child = parent1 231 } 232 233 if rand.Float64() < mutationRate { 234 child.Code = mutate(child.Code) 235 } 236 237 newPop[i] = child 238 } 239 240 population = newPop 241 } 242 243 // Final evaluation 244 for i := range population { 245 population[i].Fitness = calculateFitness(population[i].Code) 246 } 247 sort.Slice(population, func(i, j int) bool { 248 return population[i].Fitness > population[j].Fitness 249 }) 250 251 best := population[0] 252 fmt.Printf("\nā Evolution Complete!\n") 253 fmt.Printf("Best fitness: %.6f\n", best.Fitness) 254 fmt.Printf("Final length: %d chars\n", len(best.Code)) 255 fmt.Printf("\n--- EVOLVED CODE ---\n%s\n--- END ---\n", best.Code) 256 257 return nil 258 } 259 260 func initializePopulation(seed string, size int) Population { 261 pop := make(Population, size) 262 pop[0] = Individual{Code: seed} // Keep original 263 264 for i := 1; i < size; i++ { 265 mutated := seed 266 // Apply multiple random mutations 267 for j := 0; j < rand.Intn(5)+1; j++ { 268 mutated = mutate(mutated) 269 } 270 pop[i] = Individual{Code: mutated} 271 } 272 273 return pop 274 } 275 276 func tournamentSelect(pop Population) Individual { 277 tournamentSize := 3 278 best := pop[rand.Intn(len(pop))] 279 280 for i := 1; i < tournamentSize; i++ { 281 candidate := pop[rand.Intn(len(pop))] 282 if candidate.Fitness > best.Fitness { 283 best = candidate 284 } 285 } 286 287 return best 288 } 289 290 func crossover(parent1, parent2 Individual) Individual { 291 code1, code2 := parent1.Code, parent2.Code 292 293 if len(code1) == 0 || len(code2) == 0 { 294 return parent1 295 } 296 297 // Single-point crossover 298 minLen := len(code1) 299 if len(code2) < minLen { 300 minLen = len(code2) 301 } 302 303 if minLen <= 1 { 304 return parent1 305 } 306 307 point := rand.Intn(minLen-1) + 1 308 child := code1[:point] + code2[point:] 309 310 return Individual{Code: child} 311 } 312 313 func mutate(code string) string { 314 if len(code) == 0 { 315 return code 316 } 317 318 mutations := []func(string) string{ 319 insertChar, deleteChar, replaceChar, swapChars, duplicateSegment, 320 } 321 322 mutation := mutations[rand.Intn(len(mutations))] 323 return mutation(code) 324 } 325 326 func insertChar(code string) string { 327 pos := rand.Intn(len(code) + 1) 328 char := byte(rand.Intn(95) + 32) // Printable ASCII 329 return code[:pos] + string(char) + code[pos:] 330 } 331 332 func deleteChar(code string) string { 333 if len(code) <= 1 { 334 return code 335 } 336 pos := rand.Intn(len(code)) 337 return code[:pos] + code[pos+1:] 338 } 339 340 func replaceChar(code string) string { 341 if len(code) == 0 { 342 return code 343 } 344 pos := rand.Intn(len(code)) 345 char := byte(rand.Intn(95) + 32) 346 return code[:pos] + string(char) + code[pos+1:] 347 } 348 349 func swapChars(code string) string { 350 if len(code) < 2 { 351 return code 352 } 353 pos := rand.Intn(len(code) - 1) 354 chars := []byte(code) 355 chars[pos], chars[pos+1] = chars[pos+1], chars[pos] 356 return string(chars) 357 } 358 359 func duplicateSegment(code string) string { 360 if len(code) < 2 { 361 return code 362 } 363 start := rand.Intn(len(code)) 364 end := start + rand.Intn(len(code)-start) + 1 365 segment := code[start:end] 366 pos := rand.Intn(len(code) + 1) 367 return code[:pos] + segment + code[pos:] 368 } 369 370 func calculateFitness(code string) float64 { 371 if len(code) == 0 { 372 return 0 373 } 374 375 // Multi-objective fitness 376 lengthScore := 1000.0 / float64(len(code)) 377 378 // Syntax bonus (very basic) 379 syntaxScore := 0.0 380 if strings.Contains(code, "func") { 381 syntaxScore += 10 382 } 383 if strings.Contains(code, "{") && strings.Contains(code, "}") { 384 syntaxScore += 5 385 } 386 387 // Penalize invalid characters 388 penalty := 0.0 389 for _, char := range code { 390 if char < 32 || char > 126 { 391 penalty += 1 392 } 393 } 394 395 return lengthScore + syntaxScore - penalty 396 } 397 398 func avgFitness(pop Population) float64 { 399 sum := 0.0 400 for _, ind := range pop { 401 sum += ind.Fitness 402 } 403 return sum / float64(len(pop)) 404 }