// Package main is the entry point for the KAOS supervisor process. // It parses CLI commands and delegates to supervisor functions. package main import ( "fmt" "os" "path/filepath" "strings" "text/tabwriter" "github.com/dal/kaos/internal/config" "github.com/dal/kaos/internal/supervisor" ) func main() { cfg, err := config.Load() if err != nil { fmt.Fprintf(os.Stderr, "Greška pri učitavanju konfiguracije: %v\n", err) os.Exit(1) } if len(os.Args) < 2 { printHelp() os.Exit(1) } command := os.Args[1] switch command { case "run": os.Exit(cmdRun(cfg)) case "status": os.Exit(cmdStatus(cfg)) case "next": os.Exit(cmdNext(cfg)) case "verify": os.Exit(cmdVerify(cfg)) case "history": os.Exit(cmdHistory(cfg)) case "help", "--help", "-h": printHelp() default: fmt.Fprintf(os.Stderr, "Nepoznata komanda: %s\n\n", command) printHelp() os.Exit(1) } } func printHelp() { fmt.Println("KAOS Supervisor") fmt.Println() fmt.Println("Komande:") fmt.Println(" run [TASK_ID] Pokreni task (ili sledeći iz ready/)") fmt.Println(" status Prikaži status svih taskova") fmt.Println(" next Prikaži sledeći task za rad") fmt.Println(" verify [PATH] Pokreni verifikaciju na projektu") fmt.Println(" history Prikaži izvršene taskove iz reports/") fmt.Println(" help Prikaži ovu pomoć") } func cmdRun(cfg *config.Config) int { sv := supervisor.NewSupervisor(cfg) var err error if len(os.Args) > 2 { taskID := os.Args[2] fmt.Printf("▶ Pokrećem: %s\n", taskID) err = sv.Run(taskID) } else { // Check if there are any ready tasks first tasks, scanErr := supervisor.ScanTasks(cfg.TasksDir) if scanErr != nil { fmt.Fprintf(os.Stderr, "Greška pri skeniranju taskova: %v\n", scanErr) return 1 } next := supervisor.NextTask(tasks) if next == nil { fmt.Println("Nema taskova spremnih za rad") return 0 } fmt.Printf("▶ Pokrećem sledeći: %s — %s\n", next.ID, next.Title) err = sv.RunNext() } if err != nil { fmt.Fprintf(os.Stderr, "Greška: %v\n", err) return 1 } fmt.Println("\n✅ Task završen i premešten u review/") return 0 } func cmdStatus(cfg *config.Config) int { tasks, err := supervisor.ScanTasks(cfg.TasksDir) if err != nil { fmt.Fprintf(os.Stderr, "Greška pri skeniranju taskova: %v\n", err) return 1 } if len(tasks) == 0 { fmt.Println("Nema taskova") return 0 } w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) fmt.Fprintln(w, "ID\tNaslov\tFolder\tZavisi od") fmt.Fprintln(w, "──\t──────\t──────\t─────────") for _, t := range tasks { deps := "—" if len(t.DependsOn) > 0 { deps = strings.Join(t.DependsOn, ", ") } icon := statusIcon(t.Status) fmt.Fprintf(w, "%s\t%s\t%s %s\t%s\n", t.ID, t.Title, icon, t.Status, deps) } w.Flush() return 0 } func cmdNext(cfg *config.Config) int { tasks, err := supervisor.ScanTasks(cfg.TasksDir) if err != nil { fmt.Fprintf(os.Stderr, "Greška pri skeniranju taskova: %v\n", err) return 1 } task := supervisor.NextTask(tasks) if task == nil { fmt.Println("Nema taskova spremnih za rad") return 0 } fmt.Printf("Sledeći: %s — %s\n", task.ID, task.Title) fmt.Printf("Agent: %s | Model: %s\n", task.Agent, task.Model) if len(task.DependsOn) > 0 { fmt.Printf("Zavisi od: %s\n", strings.Join(task.DependsOn, ", ")) } return 0 } func cmdVerify(cfg *config.Config) int { path := cfg.ProjectPath if len(os.Args) > 2 { path = os.Args[2] } fmt.Printf("🔍 Verifikacija: %s\n\n", path) result := supervisor.Verify(path) fmt.Print(supervisor.FormatResult(result)) if !result.AllPassed { return 1 } return 0 } func cmdHistory(cfg *config.Config) int { reportsDir := filepath.Join(cfg.TasksDir, "reports") entries, err := os.ReadDir(reportsDir) if err != nil { if os.IsNotExist(err) { fmt.Println("Nema izveštaja") return 0 } fmt.Fprintf(os.Stderr, "Greška pri čitanju reports/: %v\n", err) return 1 } if len(entries) == 0 { fmt.Println("Nema izveštaja") return 0 } fmt.Println("Izveštaji:") for _, entry := range entries { if entry.IsDir() || !strings.HasSuffix(entry.Name(), "-report.md") { continue } name := strings.TrimSuffix(entry.Name(), "-report.md") fmt.Printf(" 📝 %s (%s)\n", name, filepath.Join(reportsDir, entry.Name())) } return 0 } func statusIcon(status string) string { switch status { case "done": return "✅" case "active": return "🔄" case "ready": return "📋" case "review": return "👀" case "backlog": return "📦" default: return "❓" } }