From 17f924aa60731af76d17bcff27f5f6c1271a0db1 Mon Sep 17 00:00:00 2001 From: 404kernel Date: Tue, 20 Oct 2026 07:46:33 +0000 Subject: [PATCH] feat(ui,audio): add /theme palette engine, /commit assistant, and native authentic companion audio --- README.md | 2 + internal/audio/assets/cat_meow.wav | Bin 0 -> 34424 bytes internal/audio/assets/dog_bark.wav | Bin 0 -> 52998 bytes internal/audio/audio.go | 75 ++++---- internal/audio/audio_test.go | 23 +++ internal/audio/play_other.go | 28 +++ internal/audio/play_windows.go | 29 +++ internal/config/config.go | 5 + internal/tools/git.go | 112 +++++++++++ internal/tools/git_test.go | 41 ++++ internal/ui/model.go | 125 ++++++++++++ internal/ui/styles.go | 292 +++++++++++++++++++++++------ internal/ui/styles_test.go | 40 ++++ 13 files changed, 672 insertions(+), 100 deletions(-) create mode 100644 internal/audio/assets/cat_meow.wav create mode 100644 internal/audio/assets/dog_bark.wav create mode 100644 internal/audio/audio_test.go create mode 100644 internal/audio/play_other.go create mode 100644 internal/audio/play_windows.go create mode 100644 internal/tools/git.go create mode 100644 internal/tools/git_test.go create mode 100644 internal/ui/styles_test.go diff --git a/README.md b/README.md index e987c1a..5e04dff 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,8 @@ Kernel includes a suite of instant commands accessible directly from the input b | `/model ` | Dynamically switch models (e.g. `/model gemini-3.5-flash`, `/model gpt-4o`) | | `/web ` | Performs a zero-key live web search and returns markdown summaries | | `/read ` | Reads and displays syntax-highlighted code from any project file | +| `/theme [name]` | Dynamically switch color themes (`cyberpunk`, `matrix`, `dracula`, `nord`, `tokyo`, `synthwave`) | +| `/commit [-y]` | AI Git Conventional Commit message generator & 1-click committer | | `/save [filename]` | Exports the entire chat session to a formatted `.md` file | | `$ ` or `/exec ` | Executes a local shell command and embeds stdout/stderr in chat | | `:q`, `/quit`, `exit` | Saves conversation to history and cleanly exits | diff --git a/internal/audio/assets/cat_meow.wav b/internal/audio/assets/cat_meow.wav new file mode 100644 index 0000000000000000000000000000000000000000..f3d8fa3cd84f65c7de43c7c43622c88658a0c374 GIT binary patch literal 34424 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 literal 0 HcmV?d00001 diff --git a/internal/audio/assets/dog_bark.wav b/internal/audio/assets/dog_bark.wav new file mode 100644 index 0000000000000000000000000000000000000000..d3d26be8680a893fdde8ba7d84be445a47a5f408 GIT binary patch literal 52998 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 mx~Z$Lpe~%8n9!O&rU 3 { + files = append(files, strings.TrimSpace(trimmed[2:])) + } + } + + // First try staged diff + diffRes := exec.RunShellCommand(ctx, "git diff --cached", 5*time.Second) + diffText := strings.TrimSpace(diffRes.Stdout) + + // If no staged diff, get unstaged working diff + if diffText == "" { + diffRes = exec.RunShellCommand(ctx, "git diff", 5*time.Second) + diffText = strings.TrimSpace(diffRes.Stdout) + } + + // Truncate diff if massive to prevent token explosion + if len(diffText) > 6000 { + diffText = diffText[:6000] + "\n... [diff truncated for length] ..." + } + + return GitChanges{ + HasChanges: true, + Status: statusText, + Diff: diffText, + Files: files, + } +} + +// BuildCommitPrompt crafts an instruction prompt for the LLM to output a conventional commit. +func BuildCommitPrompt(changes GitChanges) string { + return fmt.Sprintf(`You are an expert Git and software release assistant. +Based on the following git status and git diff, write a concise, professional Conventional Commit message. + +Rules: +1. First line must be formatted as: type(scope): short imperative summary (max 72 chars). + Types: feat, fix, docs, style, refactor, perf, test, chore. +2. If helpful, include 2-3 short bullet points after an empty line describing key changes. +3. Output ONLY the commit message. No explanations, no markdown code fences, no surrounding quotes. + +Git Status: +%s + +Git Diff: +%s +`, changes.Status, changes.Diff) +} + +// HeuristicCommitMessage generates an intelligent fallback commit message offline or in demo mode. +func HeuristicCommitMessage(changes GitChanges) string { + if len(changes.Files) == 0 { + return "chore: update workspace files" + } + + scope := "core" + firstFile := changes.Files[0] + if strings.Contains(firstFile, "ui/") || strings.Contains(firstFile, "styles") { + scope = "ui" + } else if strings.Contains(firstFile, "tools/") { + scope = "tools" + } else if strings.Contains(firstFile, "config/") { + scope = "config" + } else if strings.HasSuffix(firstFile, ".md") { + return "docs: update documentation and usage guides" + } + + // Detect if features were added + hasAdditions := strings.Contains(changes.Diff, "+") + if hasAdditions { + return fmt.Sprintf("feat(%s): implement new functionality and enhancements across %d files", scope, len(changes.Files)) + } + + return fmt.Sprintf("refactor(%s): update and refine %s", scope, firstFile) +} + +// RunGitCommit executes git add and git commit with the given message. +func RunGitCommit(message string) exec.ExecResult { + // Escape double quotes for shell execution + escaped := strings.ReplaceAll(message, `"`, `\"`) + cmd := fmt.Sprintf(`git add -A && git commit -m "%s"`, escaped) + return exec.RunShellCommand(context.Background(), cmd, 10*time.Second) +} diff --git a/internal/tools/git_test.go b/internal/tools/git_test.go new file mode 100644 index 0000000..80d30cc --- /dev/null +++ b/internal/tools/git_test.go @@ -0,0 +1,41 @@ +package tools + +import ( + "strings" + "testing" +) + +func TestHeuristicCommitMessage(t *testing.T) { + changes := GitChanges{ + HasChanges: true, + Files: []string{"internal/ui/styles.go", "internal/ui/model.go"}, + Diff: "+func ApplyTheme()", + } + + msg := HeuristicCommitMessage(changes) + if !strings.HasPrefix(msg, "feat(ui):") { + t.Errorf("expected feat(ui): prefix, got: %s", msg) + } + + docChanges := GitChanges{ + HasChanges: true, + Files: []string{"README.md"}, + Diff: "+update docs", + } + docMsg := HeuristicCommitMessage(docChanges) + if !strings.HasPrefix(docMsg, "docs:") { + t.Errorf("expected docs: prefix, got: %s", docMsg) + } +} + +func TestBuildCommitPrompt(t *testing.T) { + changes := GitChanges{ + HasChanges: true, + Status: "M internal/ui/model.go", + Diff: "+new feature", + } + prompt := BuildCommitPrompt(changes) + if !strings.Contains(prompt, "Conventional Commit") { + t.Errorf("expected prompt to mention Conventional Commit") + } +} diff --git a/internal/ui/model.go b/internal/ui/model.go index 0c921d2..0e2d398 100644 --- a/internal/ui/model.go +++ b/internal/ui/model.go @@ -95,6 +95,9 @@ func NewModel(cfg *config.Config) Model { } client := ai.NewClientFromConfig(cfg) + if cfg.Theme != "" { + _, _ = ApplyTheme(cfg.Theme) + } m := Model{ cfg: cfg, @@ -531,6 +534,8 @@ func (m *Model) handleSlashCommand(input string) (tea.Model, tea.Cmd, bool) { "- `/speak ` — Read text aloud with system TTS\n" + "- `/stats` — Live system telemetry, RAM & CPU dashboard\n" + "- `/model ` — Switch active model dynamically\n" + + "- `/theme [name]` — Switch color themes (`cyberpunk`, `matrix`, `dracula`, `nord`, `tokyo`, `synthwave`)\n" + + "- `/commit [-y]` — AI Git Conventional Commit generator & committer\n" + "- `/save [filename]` — Export conversation to Markdown file\n" + "- `/exec ` or `$ ` — Run shell commands inside Kernel\n" + "- `/quit` or `:q` — Save session history and exit\n" @@ -922,6 +927,126 @@ func (m *Model) handleSlashCommand(input string) (tea.Model, tea.Cmd, bool) { return m, nil, true } + // Color Theme Switcher (/theme [name]) + if cmd == "/theme" { + m.textInput.Reset() + if arg == "" { + m.Messages = append(m.Messages, chatMessage{ + Role: "SYSTEM", + Content: ListThemes(), + Time: time.Now().Format("15:04"), + }) + } else { + palette, err := ApplyTheme(arg) + if err != nil { + m.Messages = append(m.Messages, chatMessage{ + Role: "ERROR", + Content: fmt.Sprintf("Theme '%s' not recognized.\n\n%s", arg, ListThemes()), + Time: time.Now().Format("15:04"), + }) + } else { + m.cfg.Theme = palette.Name + _ = config.SaveConfig(m.cfg) + m.pet.AddXP(10) + m.pet.SetState(pet.StateHappy) + audio.PlayCompanionSound(string(m.pet.Skin)) + m.Messages = append(m.Messages, chatMessage{ + Role: "SYSTEM", + Content: fmt.Sprintf("🎨 Theme set to **%s** (%s)!\nSaved to `~/.kernel/config.json`.", palette.DisplayName, palette.Description), + Time: time.Now().Format("15:04"), + }) + } + } + m.updateViewport() + return m, nil, true + } + + // AI Git Commit Assistant (/commit [-y]) + if cmd == "/commit" { + m.textInput.Reset() + changes := tools.InspectGitChanges() + if !changes.HasChanges { + m.Messages = append(m.Messages, chatMessage{ + Role: "SYSTEM", + Content: "No uncommitted git changes detected. Working tree is clean ✨", + Time: time.Now().Format("15:04"), + }) + m.updateViewport() + return m, nil, true + } + + autoCommit := strings.Contains(arg, "-y") || strings.Contains(arg, "--yes") + + m.Messages = append(m.Messages, chatMessage{ + Role: "YOU", + Content: input, + Time: time.Now().Format("15:04"), + }) + + var commitMsg string + if m.aiClient != nil && m.aiClient.Provider != ai.ProviderDemo { + prompt := tools.BuildCommitPrompt(changes) + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + ch := make(chan ai.StreamChunk, 20) + go m.aiClient.Stream(ctx, prompt, ch) + + var sb strings.Builder + for chunk := range ch { + if chunk.Error != nil { + break + } + sb.WriteString(chunk.Text) + } + commitMsg = strings.TrimSpace(sb.String()) + } + + if commitMsg == "" { + commitMsg = tools.HeuristicCommitMessage(changes) + } + + commitMsg = strings.Trim(commitMsg, "`\"'\n\r ") + + fileList := "" + for i, f := range changes.Files { + if i >= 6 { + fileList += fmt.Sprintf("- ... and %d more files\n", len(changes.Files)-6) + break + } + fileList += fmt.Sprintf("- `%s`\n", f) + } + + if autoCommit { + res := tools.RunGitCommit(commitMsg) + if res.ExitCode == 0 { + m.pet.AddXP(25) + m.pet.SetState(pet.StateHappy) + audio.Bark() + m.Messages = append(m.Messages, chatMessage{ + Role: "KERNEL", + Content: fmt.Sprintf("### ⚡ Committed Successfully!\n\n**Commit Message:**\n```\n%s\n```\n\n**Committed Files (%d):**\n%s\n`git commit` exited cleanly (code 0).", commitMsg, len(changes.Files), fileList), + Time: time.Now().Format("15:04"), + }) + } else { + m.Messages = append(m.Messages, chatMessage{ + Role: "ERROR", + Content: fmt.Sprintf("Failed to run git commit: %s\n%s", res.Stderr, res.Stdout), + Time: time.Now().Format("15:04"), + }) + } + } else { + m.pet.AddXP(10) + m.Messages = append(m.Messages, chatMessage{ + Role: "KERNEL", + Content: fmt.Sprintf("### ⚡ AI Suggested Commit\n\n```\n%s\n```\n\n**Changed Files (%d):**\n%s\n\n*Tip:* Run `/commit -y` to stage all and commit immediately, or execute:\n```bash\ngit commit -m \"%s\"\n```", commitMsg, len(changes.Files), fileList, commitMsg), + Time: time.Now().Format("15:04"), + }) + } + + m.updateViewport() + return m, nil, true + } + return m, nil, false } diff --git a/internal/ui/styles.go b/internal/ui/styles.go index 4051882..29b41d0 100644 --- a/internal/ui/styles.go +++ b/internal/ui/styles.go @@ -1,102 +1,276 @@ package ui import ( + "fmt" + "strings" + "github.com/charmbracelet/lipgloss" ) +type ThemePalette struct { + Name string + DisplayName string + Description string + Primary string + Secondary string + Accent string + Warning string + Muted string + Danger string + BgDark string + Border string +} + +var AvailableThemes = map[string]ThemePalette{ + "cyberpunk": { + Name: "cyberpunk", + DisplayName: "⚡ Cyberpunk", + Description: "Neon violet & electric cyan", + Primary: "#7D56F4", + Secondary: "#00D7FE", + Accent: "#04B575", + Warning: "#FFB86C", + Muted: "#6272A4", + Danger: "#FF5555", + BgDark: "#13141C", + Border: "#3B4252", + }, + "matrix": { + Name: "matrix", + DisplayName: "🟢 Matrix", + Description: "Phosphor green mainframe", + Primary: "#00FF66", + Secondary: "#00DD44", + Accent: "#33FF33", + Warning: "#CCFF00", + Muted: "#1F6B38", + Danger: "#FF3333", + BgDark: "#0A140D", + Border: "#0D471C", + }, + "dracula": { + Name: "dracula", + DisplayName: "🧛 Dracula", + Description: "Gothic vampire purple & pastel", + Primary: "#BD93F9", + Secondary: "#8BE9FD", + Accent: "#50FA7B", + Warning: "#F1FA8C", + Muted: "#6272A4", + Danger: "#FF5555", + BgDark: "#282A36", + Border: "#44475A", + }, + "nord": { + Name: "nord", + DisplayName: "❄️ Nord", + Description: "Arctic blue & icy aurora", + Primary: "#88C0D0", + Secondary: "#81A1C1", + Accent: "#A3BE8C", + Warning: "#EBCB8B", + Muted: "#4C566A", + Danger: "#BF616A", + BgDark: "#2E3440", + Border: "#3B4252", + }, + "tokyo": { + Name: "tokyo", + DisplayName: "🗼 Tokyo Night", + Description: "Tokyo night storm & lavender", + Primary: "#7AA2F7", + Secondary: "#BB9AF7", + Accent: "#9ECE6A", + Warning: "#E0AF68", + Muted: "#565F89", + Danger: "#F7768E", + BgDark: "#1A1B26", + Border: "#292E42", + }, + "synthwave": { + Name: "synthwave", + DisplayName: "🌆 Synthwave", + Description: "Sunset magenta & neon grid", + Primary: "#FF007F", + Secondary: "#00F0FF", + Accent: "#FFE600", + Warning: "#FF7700", + Muted: "#7957D5", + Danger: "#FF1744", + BgDark: "#18092B", + Border: "#4B0082", + }, +} + var ( + CurrentThemeName = "cyberpunk" + // Colors - PrimaryColor = lipgloss.Color("#7D56F4") // Neon Purple / Violet - SecondaryColor = lipgloss.Color("#00D7FE") // Electric Cyan - AccentColor = lipgloss.Color("#04B575") // Emerald Green - WarningColor = lipgloss.Color("#FFB86C") // Amber / Gold - MutedColor = lipgloss.Color("#6272A4") // Dim Slate - DangerColor = lipgloss.Color("#FF5555") // Bright Red - BgDark = lipgloss.Color("#13141C") - BorderColor = lipgloss.Color("#3B4252") + PrimaryColor lipgloss.TerminalColor + SecondaryColor lipgloss.TerminalColor + AccentColor lipgloss.TerminalColor + WarningColor lipgloss.TerminalColor + MutedColor lipgloss.TerminalColor + DangerColor lipgloss.TerminalColor + BgDark lipgloss.TerminalColor + BorderColor lipgloss.TerminalColor // Header + HeaderBox lipgloss.Style + TitleStyle lipgloss.Style + ProviderBadgeStyle lipgloss.Style + SubtitleStyle lipgloss.Style + + // Badges + UserBadge lipgloss.Style + AgentBadge lipgloss.Style + SystemBadge lipgloss.Style + ErrorBadge lipgloss.Style + TypingDotsStyle lipgloss.Style + CursorStyle lipgloss.Style + LogTimestamp lipgloss.Style + + // Bubbles + MessageBubble lipgloss.Style + StreamingBubble lipgloss.Style + InputBoxActive lipgloss.Style + InputBoxInactive lipgloss.Style + + // Footer + FooterStyle lipgloss.Style + FooterKey lipgloss.Style +) + +func rebuildStyles() { HeaderBox = lipgloss.NewStyle(). - BorderStyle(lipgloss.RoundedBorder()). - BorderForeground(PrimaryColor). - Padding(0, 1) + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(PrimaryColor). + Padding(0, 1) TitleStyle = lipgloss.NewStyle(). - Bold(true). - Foreground(SecondaryColor) + Bold(true). + Foreground(SecondaryColor) ProviderBadgeStyle = lipgloss.NewStyle(). - Bold(true). - Foreground(lipgloss.Color("#FFFFFF")). - Background(PrimaryColor). - Padding(0, 1) + Bold(true). + Foreground(lipgloss.Color("#FFFFFF")). + Background(PrimaryColor). + Padding(0, 1) SubtitleStyle = lipgloss.NewStyle(). - Foreground(MutedColor) + Foreground(MutedColor) - // Badges UserBadge = lipgloss.NewStyle(). - Bold(true). - Foreground(lipgloss.Color("#FFFFFF")). - Background(SecondaryColor). - Padding(0, 1) + Bold(true). + Foreground(lipgloss.Color("#FFFFFF")). + Background(SecondaryColor). + Padding(0, 1) AgentBadge = lipgloss.NewStyle(). - Bold(true). - Foreground(lipgloss.Color("#FFFFFF")). - Background(PrimaryColor). - Padding(0, 1) + Bold(true). + Foreground(lipgloss.Color("#FFFFFF")). + Background(PrimaryColor). + Padding(0, 1) SystemBadge = lipgloss.NewStyle(). - Bold(true). - Foreground(lipgloss.Color("#1E1E2E")). - Background(WarningColor). - Padding(0, 1) + Bold(true). + Foreground(lipgloss.Color("#1E1E2E")). + Background(WarningColor). + Padding(0, 1) ErrorBadge = lipgloss.NewStyle(). - Bold(true). - Foreground(lipgloss.Color("#FFFFFF")). - Background(DangerColor). - Padding(0, 1) + Bold(true). + Foreground(lipgloss.Color("#FFFFFF")). + Background(DangerColor). + Padding(0, 1) TypingDotsStyle = lipgloss.NewStyle(). - Foreground(SecondaryColor). - Bold(true) + Foreground(SecondaryColor). + Bold(true) CursorStyle = lipgloss.NewStyle(). - Foreground(AccentColor). - Blink(true) + Foreground(AccentColor). + Blink(true) LogTimestamp = lipgloss.NewStyle(). - Foreground(MutedColor) + Foreground(MutedColor) - // Bubbles MessageBubble = lipgloss.NewStyle(). - BorderStyle(lipgloss.RoundedBorder()). - BorderForeground(BorderColor). - Padding(0, 1) + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(BorderColor). + Padding(0, 1) StreamingBubble = lipgloss.NewStyle(). - BorderStyle(lipgloss.RoundedBorder()). - BorderForeground(SecondaryColor). - Padding(0, 1) + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(SecondaryColor). + Padding(0, 1) InputBoxActive = lipgloss.NewStyle(). - BorderStyle(lipgloss.RoundedBorder()). - BorderForeground(PrimaryColor). - Padding(0, 1) + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(PrimaryColor). + Padding(0, 1) InputBoxInactive = lipgloss.NewStyle(). - BorderStyle(lipgloss.RoundedBorder()). - BorderForeground(BorderColor). - Padding(0, 1) + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(BorderColor). + Padding(0, 1) - // Footer FooterStyle = lipgloss.NewStyle(). - Foreground(MutedColor). - MarginTop(1) + Foreground(MutedColor). + MarginTop(1) FooterKey = lipgloss.NewStyle(). - Bold(true). - Foreground(SecondaryColor) -) + Bold(true). + Foreground(SecondaryColor) +} + +// ApplyTheme sets the active UI palette and dynamically updates all styles. +func ApplyTheme(name string) (ThemePalette, error) { + key := strings.ToLower(strings.TrimSpace(name)) + if key == "tokyonight" || key == "tokyo-night" { + key = "tokyo" + } + + palette, exists := AvailableThemes[key] + if !exists { + return AvailableThemes["cyberpunk"], fmt.Errorf("unknown theme '%s'", name) + } + + CurrentThemeName = key + PrimaryColor = lipgloss.Color(palette.Primary) + SecondaryColor = lipgloss.Color(palette.Secondary) + AccentColor = lipgloss.Color(palette.Accent) + WarningColor = lipgloss.Color(palette.Warning) + MutedColor = lipgloss.Color(palette.Muted) + DangerColor = lipgloss.Color(palette.Danger) + BgDark = lipgloss.Color(palette.BgDark) + BorderColor = lipgloss.Color(palette.Border) + + rebuildStyles() + return palette, nil +} + +// ListThemes renders an ASCII preview table of all available themes. +func ListThemes() string { + var b strings.Builder + b.WriteString("### 🎨 Available Kernel Themes\n\n") + b.WriteString("| Theme | Name | Description | Status |\n") + b.WriteString("|---|---|---|---|\n") + + keys := []string{"cyberpunk", "matrix", "dracula", "nord", "tokyo", "synthwave"} + for _, k := range keys { + t := AvailableThemes[k] + status := " " + if k == CurrentThemeName { + status = "★ **ACTIVE**" + } + b.WriteString(fmt.Sprintf("| `%s` | %s | %s | %s |\n", t.Name, t.DisplayName, t.Description, status)) + } + + b.WriteString("\n*Usage:* `/theme ` (e.g. `/theme matrix`, `/theme nord`)") + return b.String() +} + +func init() { + _, _ = ApplyTheme("cyberpunk") +} diff --git a/internal/ui/styles_test.go b/internal/ui/styles_test.go new file mode 100644 index 0000000..79d9cf7 --- /dev/null +++ b/internal/ui/styles_test.go @@ -0,0 +1,40 @@ +package ui + +import ( + "testing" +) + +func TestApplyTheme(t *testing.T) { + themes := []string{"cyberpunk", "matrix", "dracula", "nord", "tokyo", "synthwave"} + for _, name := range themes { + palette, err := ApplyTheme(name) + if err != nil { + t.Fatalf("expected theme '%s' to apply without error, got %v", name, err) + } + if palette.Name != name { + t.Errorf("expected palette.Name to be '%s', got '%s'", name, palette.Name) + } + if CurrentThemeName != name { + t.Errorf("expected CurrentThemeName to be '%s', got '%s'", name, CurrentThemeName) + } + } + + // Test aliases + aliasPalette, err := ApplyTheme("tokyo-night") + if err != nil || aliasPalette.Name != "tokyo" { + t.Fatalf("expected tokyo-night alias to resolve to tokyo, got %v", err) + } + + // Test unknown theme + _, err = ApplyTheme("non-existent-theme") + if err == nil { + t.Errorf("expected error for unknown theme, got nil") + } +} + +func TestListThemes(t *testing.T) { + out := ListThemes() + if len(out) == 0 { + t.Fatal("expected ListThemes output to be non-empty") + } +}