adamdottv 9 месяцев назад
Родитель
Сommit
8cbfc581b5

+ 0 - 1
internal/config/init.go

@@ -58,4 +58,3 @@ func MarkProjectInitialized() error {
 
 
 	return nil
 	return nil
 }
 }
-

+ 0 - 2
internal/llm/agent/agent-tool.go

@@ -88,8 +88,6 @@ func (b *agentTool) Run(ctx context.Context, call tools.ToolCall) (tools.ToolRes
 	}
 	}
 
 
 	parentSession.Cost += updatedSession.Cost
 	parentSession.Cost += updatedSession.Cost
-	parentSession.PromptTokens += updatedSession.PromptTokens
-	parentSession.CompletionTokens += updatedSession.CompletionTokens
 
 
 	_, err = b.sessions.Update(ctx, parentSession)
 	_, err = b.sessions.Update(ctx, parentSession)
 	if err != nil {
 	if err != nil {

+ 13 - 51
internal/llm/agent/agent.go

@@ -300,53 +300,6 @@ func (a *agent) createUserMessage(ctx context.Context, sessionID, content string
 }
 }
 
 
 func (a *agent) streamAndHandleEvents(ctx context.Context, sessionID string, msgHistory []message.Message) (message.Message, *message.Message, error) {
 func (a *agent) streamAndHandleEvents(ctx context.Context, sessionID string, msgHistory []message.Message) (message.Message, *message.Message, error) {
-	// Check if we need to auto-compact based on token count
-	contextWindow := a.provider.Model().ContextWindow
-	maxTokens := a.provider.MaxTokens()
-	threshold := int64(float64(contextWindow) * 0.80)
-	usage, err := a.GetUsage(ctx, sessionID)
-	if err != nil || usage == nil {
-		return message.Message{}, nil, fmt.Errorf("failed to get usage: %w", err)
-	}
-
-	// If we're approaching the context window limit, trigger auto-compaction
-	if false && (*usage+maxTokens) >= threshold {
-		status.Info(fmt.Sprintf("Auto-compaction triggered for session %s. Estimated tokens: %d, Threshold: %d", sessionID, usage, threshold))
-
-		// Perform compaction with pause/resume to ensure safety
-		if err := a.CompactSession(ctx, sessionID); err != nil {
-			status.Error(fmt.Sprintf("Auto-compaction failed: %v", err))
-			// Continue with the request even if compaction fails
-		} else {
-			// Re-fetch session details after compaction
-			currentSession, err := a.sessions.Get(ctx, sessionID)
-			if err != nil {
-				return message.Message{}, nil, fmt.Errorf("failed to get session after compaction: %w", err)
-			}
-
-			// Re-prepare messages using the new summary
-			var sessionMessages []message.Message
-			if currentSession.Summary != "" && currentSession.SummarizedAt > 0 {
-				// If summary exists, only fetch messages after the summarization timestamp
-				sessionMessages, err = a.messages.ListAfter(ctx, sessionID, currentSession.SummarizedAt)
-				if err != nil {
-					return message.Message{}, nil, fmt.Errorf("failed to list messages after compaction: %w", err)
-				}
-
-				// Create a new message history with the summary and messages after summarization
-				summaryMessage := message.Message{
-					Role: message.Assistant,
-					Parts: []message.ContentPart{
-						message.TextContent{Text: currentSession.Summary},
-					},
-				}
-
-				// Replace msgHistory with the new compacted version
-				msgHistory = append([]message.Message{summaryMessage}, sessionMessages...)
-			}
-		}
-	}
-
 	eventChan := a.provider.StreamResponse(ctx, msgHistory, a.tools)
 	eventChan := a.provider.StreamResponse(ctx, msgHistory, a.tools)
 
 
 	assistantMsg, err := a.messages.Create(ctx, sessionID, message.CreateMessageParams{
 	assistantMsg, err := a.messages.Create(ctx, sessionID, message.CreateMessageParams{
@@ -541,8 +494,8 @@ func (a *agent) TrackUsage(ctx context.Context, sessionID string, model models.M
 		model.CostPer1MOut/1e6*float64(usage.OutputTokens)
 		model.CostPer1MOut/1e6*float64(usage.OutputTokens)
 
 
 	sess.Cost += cost
 	sess.Cost += cost
-	sess.CompletionTokens += usage.OutputTokens
-	sess.PromptTokens += usage.InputTokens
+	sess.CompletionTokens = usage.OutputTokens + usage.CacheReadTokens
+	sess.PromptTokens = usage.InputTokens + usage.CacheCreationTokens
 
 
 	_, err = a.sessions.Update(ctx, sess)
 	_, err = a.sessions.Update(ctx, sess)
 	if err != nil {
 	if err != nil {
@@ -646,7 +599,16 @@ func (a *agent) CompactSession(ctx context.Context, sessionID string) error {
 			Role: message.System,
 			Role: message.System,
 			Parts: []message.ContentPart{
 			Parts: []message.ContentPart{
 				message.TextContent{
 				message.TextContent{
-					Text: "You are a helpful AI assistant tasked with summarizing conversations.",
+					Text: `You are a helpful AI assistant tasked with summarizing conversations.
+
+When asked to summarize, provide a detailed but concise summary of the conversation. 
+Focus on information that would be helpful for continuing the conversation, including:
+- What was done
+- What is currently being worked on
+- Which files are being modified
+- What needs to be done next
+
+Your summary should be comprehensive enough to provide context but concise enough to be quickly understood.`,
 				},
 				},
 			},
 			},
 		},
 		},
@@ -655,7 +617,7 @@ func (a *agent) CompactSession(ctx context.Context, sessionID string) error {
 	// If there's an existing summary, include it
 	// If there's an existing summary, include it
 	if existingSummary != "" {
 	if existingSummary != "" {
 		messages = append(messages, message.Message{
 		messages = append(messages, message.Message{
-			Role: message.Assistant, // TODO: should this be system or user instead?
+			Role: message.Assistant,
 			Parts: []message.ContentPart{
 			Parts: []message.ContentPart{
 				message.TextContent{
 				message.TextContent{
 					Text: existingSummary,
 					Text: existingSummary,

+ 0 - 1
internal/llm/provider/bedrock.go

@@ -98,4 +98,3 @@ func (b *bedrockClient) stream(ctx context.Context, messages []message.Message,
 
 
 	return b.childProvider.stream(ctx, messages, tools)
 	return b.childProvider.stream(ctx, messages, tools)
 }
 }
-

+ 23 - 23
internal/llm/tools/ls_test.go

@@ -83,19 +83,19 @@ func TestLsTool_Run(t *testing.T) {
 
 
 		response, err := tool.Run(context.Background(), call)
 		response, err := tool.Run(context.Background(), call)
 		require.NoError(t, err)
 		require.NoError(t, err)
-		
+
 		// Check that visible directories and files are included
 		// Check that visible directories and files are included
 		assert.Contains(t, response.Content, "dir1")
 		assert.Contains(t, response.Content, "dir1")
 		assert.Contains(t, response.Content, "dir2")
 		assert.Contains(t, response.Content, "dir2")
 		assert.Contains(t, response.Content, "dir3")
 		assert.Contains(t, response.Content, "dir3")
 		assert.Contains(t, response.Content, "file1.txt")
 		assert.Contains(t, response.Content, "file1.txt")
 		assert.Contains(t, response.Content, "file2.txt")
 		assert.Contains(t, response.Content, "file2.txt")
-		
+
 		// Check that hidden files and directories are not included
 		// Check that hidden files and directories are not included
 		assert.NotContains(t, response.Content, ".hidden_dir")
 		assert.NotContains(t, response.Content, ".hidden_dir")
 		assert.NotContains(t, response.Content, ".hidden_file.txt")
 		assert.NotContains(t, response.Content, ".hidden_file.txt")
 		assert.NotContains(t, response.Content, ".hidden_root_file.txt")
 		assert.NotContains(t, response.Content, ".hidden_root_file.txt")
-		
+
 		// Check that __pycache__ is not included
 		// Check that __pycache__ is not included
 		assert.NotContains(t, response.Content, "__pycache__")
 		assert.NotContains(t, response.Content, "__pycache__")
 	})
 	})
@@ -122,7 +122,7 @@ func TestLsTool_Run(t *testing.T) {
 	t.Run("handles empty path parameter", func(t *testing.T) {
 	t.Run("handles empty path parameter", func(t *testing.T) {
 		// For this test, we need to mock the config.WorkingDirectory function
 		// For this test, we need to mock the config.WorkingDirectory function
 		// Since we can't easily do that, we'll just check that the response doesn't contain an error message
 		// Since we can't easily do that, we'll just check that the response doesn't contain an error message
-		
+
 		tool := NewLsTool()
 		tool := NewLsTool()
 		params := LSParams{
 		params := LSParams{
 			Path: "",
 			Path: "",
@@ -138,7 +138,7 @@ func TestLsTool_Run(t *testing.T) {
 
 
 		response, err := tool.Run(context.Background(), call)
 		response, err := tool.Run(context.Background(), call)
 		require.NoError(t, err)
 		require.NoError(t, err)
-		
+
 		// The response should either contain a valid directory listing or an error
 		// The response should either contain a valid directory listing or an error
 		// We'll just check that it's not empty
 		// We'll just check that it's not empty
 		assert.NotEmpty(t, response.Content)
 		assert.NotEmpty(t, response.Content)
@@ -173,11 +173,11 @@ func TestLsTool_Run(t *testing.T) {
 
 
 		response, err := tool.Run(context.Background(), call)
 		response, err := tool.Run(context.Background(), call)
 		require.NoError(t, err)
 		require.NoError(t, err)
-		
+
 		// The output format is a tree, so we need to check for specific patterns
 		// The output format is a tree, so we need to check for specific patterns
 		// Check that file1.txt is not directly mentioned
 		// Check that file1.txt is not directly mentioned
 		assert.NotContains(t, response.Content, "- file1.txt")
 		assert.NotContains(t, response.Content, "- file1.txt")
-		
+
 		// Check that dir1/ is not directly mentioned
 		// Check that dir1/ is not directly mentioned
 		assert.NotContains(t, response.Content, "- dir1/")
 		assert.NotContains(t, response.Content, "- dir1/")
 	})
 	})
@@ -189,12 +189,12 @@ func TestLsTool_Run(t *testing.T) {
 		defer func() {
 		defer func() {
 			os.Chdir(origWd)
 			os.Chdir(origWd)
 		}()
 		}()
-		
+
 		// Change to a directory above the temp directory
 		// Change to a directory above the temp directory
 		parentDir := filepath.Dir(tempDir)
 		parentDir := filepath.Dir(tempDir)
 		err = os.Chdir(parentDir)
 		err = os.Chdir(parentDir)
 		require.NoError(t, err)
 		require.NoError(t, err)
-		
+
 		tool := NewLsTool()
 		tool := NewLsTool()
 		params := LSParams{
 		params := LSParams{
 			Path: filepath.Base(tempDir),
 			Path: filepath.Base(tempDir),
@@ -210,7 +210,7 @@ func TestLsTool_Run(t *testing.T) {
 
 
 		response, err := tool.Run(context.Background(), call)
 		response, err := tool.Run(context.Background(), call)
 		require.NoError(t, err)
 		require.NoError(t, err)
-		
+
 		// Should list the temp directory contents
 		// Should list the temp directory contents
 		assert.Contains(t, response.Content, "dir1")
 		assert.Contains(t, response.Content, "dir1")
 		assert.Contains(t, response.Content, "file1.txt")
 		assert.Contains(t, response.Content, "file1.txt")
@@ -291,22 +291,22 @@ func TestCreateFileTree(t *testing.T) {
 	}
 	}
 
 
 	tree := createFileTree(paths)
 	tree := createFileTree(paths)
-	
+
 	// Check the structure of the tree
 	// Check the structure of the tree
 	assert.Len(t, tree, 1) // Should have one root node
 	assert.Len(t, tree, 1) // Should have one root node
-	
+
 	// Check the root node
 	// Check the root node
 	rootNode := tree[0]
 	rootNode := tree[0]
 	assert.Equal(t, "path", rootNode.Name)
 	assert.Equal(t, "path", rootNode.Name)
 	assert.Equal(t, "directory", rootNode.Type)
 	assert.Equal(t, "directory", rootNode.Type)
 	assert.Len(t, rootNode.Children, 1)
 	assert.Len(t, rootNode.Children, 1)
-	
+
 	// Check the "to" node
 	// Check the "to" node
 	toNode := rootNode.Children[0]
 	toNode := rootNode.Children[0]
 	assert.Equal(t, "to", toNode.Name)
 	assert.Equal(t, "to", toNode.Name)
 	assert.Equal(t, "directory", toNode.Type)
 	assert.Equal(t, "directory", toNode.Type)
 	assert.Len(t, toNode.Children, 3) // file1.txt, dir1, dir2
 	assert.Len(t, toNode.Children, 3) // file1.txt, dir1, dir2
-	
+
 	// Find the dir1 node
 	// Find the dir1 node
 	var dir1Node *TreeNode
 	var dir1Node *TreeNode
 	for _, child := range toNode.Children {
 	for _, child := range toNode.Children {
@@ -315,7 +315,7 @@ func TestCreateFileTree(t *testing.T) {
 			break
 			break
 		}
 		}
 	}
 	}
-	
+
 	require.NotNil(t, dir1Node)
 	require.NotNil(t, dir1Node)
 	assert.Equal(t, "directory", dir1Node.Type)
 	assert.Equal(t, "directory", dir1Node.Type)
 	assert.Len(t, dir1Node.Children, 2) // file2.txt and subdir
 	assert.Len(t, dir1Node.Children, 2) // file2.txt and subdir
@@ -354,9 +354,9 @@ func TestPrintTree(t *testing.T) {
 			Type: "file",
 			Type: "file",
 		},
 		},
 	}
 	}
-	
+
 	result := printTree(tree, "/root")
 	result := printTree(tree, "/root")
-	
+
 	// Check the output format
 	// Check the output format
 	assert.Contains(t, result, "- /root/")
 	assert.Contains(t, result, "- /root/")
 	assert.Contains(t, result, "  - dir1/")
 	assert.Contains(t, result, "  - dir1/")
@@ -405,7 +405,7 @@ func TestListDirectory(t *testing.T) {
 		files, truncated, err := listDirectory(tempDir, []string{}, 1000)
 		files, truncated, err := listDirectory(tempDir, []string{}, 1000)
 		require.NoError(t, err)
 		require.NoError(t, err)
 		assert.False(t, truncated)
 		assert.False(t, truncated)
-		
+
 		// Check that visible files and directories are included
 		// Check that visible files and directories are included
 		containsPath := func(paths []string, target string) bool {
 		containsPath := func(paths []string, target string) bool {
 			targetPath := filepath.Join(tempDir, target)
 			targetPath := filepath.Join(tempDir, target)
@@ -416,12 +416,12 @@ func TestListDirectory(t *testing.T) {
 			}
 			}
 			return false
 			return false
 		}
 		}
-		
+
 		assert.True(t, containsPath(files, "dir1"))
 		assert.True(t, containsPath(files, "dir1"))
 		assert.True(t, containsPath(files, "file1.txt"))
 		assert.True(t, containsPath(files, "file1.txt"))
 		assert.True(t, containsPath(files, "file2.txt"))
 		assert.True(t, containsPath(files, "file2.txt"))
 		assert.True(t, containsPath(files, "dir1/file3.txt"))
 		assert.True(t, containsPath(files, "dir1/file3.txt"))
-		
+
 		// Check that hidden files and directories are not included
 		// Check that hidden files and directories are not included
 		assert.False(t, containsPath(files, ".hidden_dir"))
 		assert.False(t, containsPath(files, ".hidden_dir"))
 		assert.False(t, containsPath(files, ".hidden_file.txt"))
 		assert.False(t, containsPath(files, ".hidden_file.txt"))
@@ -438,12 +438,12 @@ func TestListDirectory(t *testing.T) {
 		files, truncated, err := listDirectory(tempDir, []string{"*.txt"}, 1000)
 		files, truncated, err := listDirectory(tempDir, []string{"*.txt"}, 1000)
 		require.NoError(t, err)
 		require.NoError(t, err)
 		assert.False(t, truncated)
 		assert.False(t, truncated)
-		
+
 		// Check that no .txt files are included
 		// Check that no .txt files are included
 		for _, file := range files {
 		for _, file := range files {
 			assert.False(t, strings.HasSuffix(file, ".txt"), "Found .txt file: %s", file)
 			assert.False(t, strings.HasSuffix(file, ".txt"), "Found .txt file: %s", file)
 		}
 		}
-		
+
 		// But directories should still be included
 		// But directories should still be included
 		containsDir := false
 		containsDir := false
 		for _, file := range files {
 		for _, file := range files {
@@ -454,4 +454,4 @@ func TestListDirectory(t *testing.T) {
 		}
 		}
 		assert.True(t, containsDir)
 		assert.True(t, containsDir)
 	})
 	})
-}
+}

+ 0 - 11
internal/logging/logging.go

@@ -11,7 +11,6 @@ import (
 	"os"
 	"os"
 	"runtime/debug"
 	"runtime/debug"
 	"strings"
 	"strings"
-	"sync"
 	"time"
 	"time"
 
 
 	"github.com/go-logfmt/logfmt"
 	"github.com/go-logfmt/logfmt"
@@ -45,7 +44,6 @@ type Service interface {
 type service struct {
 type service struct {
 	db     *db.Queries
 	db     *db.Queries
 	broker *pubsub.Broker[Log]
 	broker *pubsub.Broker[Log]
-	mu     sync.RWMutex
 }
 }
 
 
 var globalLoggingService *service
 var globalLoggingService *service
@@ -72,9 +70,6 @@ func GetService() Service {
 }
 }
 
 
 func (s *service) Create(ctx context.Context, log Log) error {
 func (s *service) Create(ctx context.Context, log Log) error {
-	s.mu.Lock()
-	defer s.mu.Unlock()
-
 	if log.ID == "" {
 	if log.ID == "" {
 		log.ID = uuid.New().String()
 		log.ID = uuid.New().String()
 	}
 	}
@@ -115,9 +110,6 @@ func (s *service) Create(ctx context.Context, log Log) error {
 }
 }
 
 
 func (s *service) ListBySession(ctx context.Context, sessionID string) ([]Log, error) {
 func (s *service) ListBySession(ctx context.Context, sessionID string) ([]Log, error) {
-	s.mu.RLock()
-	defer s.mu.RUnlock()
-
 	dbLogs, err := s.db.ListLogsBySession(ctx, sql.NullString{String: sessionID, Valid: true})
 	dbLogs, err := s.db.ListLogsBySession(ctx, sql.NullString{String: sessionID, Valid: true})
 	if err != nil {
 	if err != nil {
 		return nil, fmt.Errorf("db.ListLogsBySession: %w", err)
 		return nil, fmt.Errorf("db.ListLogsBySession: %w", err)
@@ -126,9 +118,6 @@ func (s *service) ListBySession(ctx context.Context, sessionID string) ([]Log, e
 }
 }
 
 
 func (s *service) ListAll(ctx context.Context, limit int) ([]Log, error) {
 func (s *service) ListAll(ctx context.Context, limit int) ([]Log, error) {
-	s.mu.RLock()
-	defer s.mu.RUnlock()
-
 	dbLogs, err := s.db.ListAllLogs(ctx, int64(limit))
 	dbLogs, err := s.db.ListAllLogs(ctx, int64(limit))
 	if err != nil {
 	if err != nil {
 		return nil, fmt.Errorf("db.ListAllLogs: %w", err)
 		return nil, fmt.Errorf("db.ListAllLogs: %w", err)

+ 0 - 1
internal/lsp/discovery/language.go

@@ -296,4 +296,3 @@ func GetLanguageIDFromPath(path string) string {
 	langKind := lsp.DetectLanguageID(uri)
 	langKind := lsp.DetectLanguageID(uri)
 	return GetLanguageIDFromProtocol(string(langKind))
 	return GetLanguageIDFromProtocol(string(langKind))
 }
 }
-

+ 0 - 1
internal/lsp/discovery/server.go

@@ -304,4 +304,3 @@ func ConfigureLSPServers(rootDir string) (map[string]ServerInfo, error) {
 
 
 	return servers, nil
 	return servers, nil
 }
 }
-

+ 0 - 1
internal/pubsub/broker_test.go

@@ -142,4 +142,3 @@ func TestBrokerConcurrency(t *testing.T) {
 	}
 	}
 	assert.Equal(t, numSubscribers, count)
 	assert.Equal(t, numSubscribers, count)
 }
 }
-

+ 0 - 1
internal/tui/components/dialog/arguments.go

@@ -170,4 +170,3 @@ type ShowArgumentsDialogMsg struct {
 	CommandID string
 	CommandID string
 	Content   string
 	Content   string
 }
 }
-

+ 1 - 1
internal/tui/components/dialog/commands.go

@@ -115,7 +115,7 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 func (c *commandDialogCmp) View() string {
 func (c *commandDialogCmp) View() string {
 	t := theme.CurrentTheme()
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 	baseStyle := styles.BaseStyle()
-	
+
 	if len(c.commands) == 0 {
 	if len(c.commands) == 0 {
 		return baseStyle.Padding(1, 2).
 		return baseStyle.Padding(1, 2).
 			Border(lipgloss.RoundedBorder()).
 			Border(lipgloss.RoundedBorder()).

+ 1 - 1
internal/tui/components/dialog/init.go

@@ -95,7 +95,7 @@ func (m InitDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 func (m InitDialogCmp) View() string {
 func (m InitDialogCmp) View() string {
 	t := theme.CurrentTheme()
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 	baseStyle := styles.BaseStyle()
-	
+
 	// Calculate width needed for content
 	// Calculate width needed for content
 	maxWidth := 60 // Width for explanation text
 	maxWidth := 60 // Width for explanation text
 
 

+ 9 - 9
internal/tui/components/dialog/permission.go

@@ -150,7 +150,7 @@ func (p *permissionDialogCmp) selectCurrentOption() tea.Cmd {
 func (p *permissionDialogCmp) renderButtons() string {
 func (p *permissionDialogCmp) renderButtons() string {
 	t := theme.CurrentTheme()
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 	baseStyle := styles.BaseStyle()
-	
+
 	allowStyle := baseStyle
 	allowStyle := baseStyle
 	allowSessionStyle := baseStyle
 	allowSessionStyle := baseStyle
 	denyStyle := baseStyle
 	denyStyle := baseStyle
@@ -196,7 +196,7 @@ func (p *permissionDialogCmp) renderButtons() string {
 func (p *permissionDialogCmp) renderHeader() string {
 func (p *permissionDialogCmp) renderHeader() string {
 	t := theme.CurrentTheme()
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 	baseStyle := styles.BaseStyle()
-	
+
 	toolKey := baseStyle.Foreground(t.TextMuted()).Bold(true).Render("Tool")
 	toolKey := baseStyle.Foreground(t.TextMuted()).Bold(true).Render("Tool")
 	toolValue := baseStyle.
 	toolValue := baseStyle.
 		Foreground(t.Text()).
 		Foreground(t.Text()).
@@ -242,13 +242,13 @@ func (p *permissionDialogCmp) renderHeader() string {
 func (p *permissionDialogCmp) renderBashContent() string {
 func (p *permissionDialogCmp) renderBashContent() string {
 	t := theme.CurrentTheme()
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 	baseStyle := styles.BaseStyle()
-	
+
 	if pr, ok := p.permission.Params.(tools.BashPermissionsParams); ok {
 	if pr, ok := p.permission.Params.(tools.BashPermissionsParams); ok {
 		content := fmt.Sprintf("```bash\n%s\n```", pr.Command)
 		content := fmt.Sprintf("```bash\n%s\n```", pr.Command)
 
 
 		// Use the cache for markdown rendering
 		// Use the cache for markdown rendering
 		renderedContent := p.GetOrSetMarkdown(p.permission.ID, func() (string, error) {
 		renderedContent := p.GetOrSetMarkdown(p.permission.ID, func() (string, error) {
-			r := styles.GetMarkdownRenderer(p.width-10)
+			r := styles.GetMarkdownRenderer(p.width - 10)
 			s, err := r.Render(content)
 			s, err := r.Render(content)
 			return styles.ForceReplaceBackgroundWithLipgloss(s, t.Background()), err
 			return styles.ForceReplaceBackgroundWithLipgloss(s, t.Background()), err
 		})
 		})
@@ -302,13 +302,13 @@ func (p *permissionDialogCmp) renderWriteContent() string {
 func (p *permissionDialogCmp) renderFetchContent() string {
 func (p *permissionDialogCmp) renderFetchContent() string {
 	t := theme.CurrentTheme()
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 	baseStyle := styles.BaseStyle()
-	
+
 	if pr, ok := p.permission.Params.(tools.FetchPermissionsParams); ok {
 	if pr, ok := p.permission.Params.(tools.FetchPermissionsParams); ok {
 		content := fmt.Sprintf("```bash\n%s\n```", pr.URL)
 		content := fmt.Sprintf("```bash\n%s\n```", pr.URL)
 
 
 		// Use the cache for markdown rendering
 		// Use the cache for markdown rendering
 		renderedContent := p.GetOrSetMarkdown(p.permission.ID, func() (string, error) {
 		renderedContent := p.GetOrSetMarkdown(p.permission.ID, func() (string, error) {
-			r := styles.GetMarkdownRenderer(p.width-10)
+			r := styles.GetMarkdownRenderer(p.width - 10)
 			s, err := r.Render(content)
 			s, err := r.Render(content)
 			return styles.ForceReplaceBackgroundWithLipgloss(s, t.Background()), err
 			return styles.ForceReplaceBackgroundWithLipgloss(s, t.Background()), err
 		})
 		})
@@ -325,12 +325,12 @@ func (p *permissionDialogCmp) renderFetchContent() string {
 func (p *permissionDialogCmp) renderDefaultContent() string {
 func (p *permissionDialogCmp) renderDefaultContent() string {
 	t := theme.CurrentTheme()
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 	baseStyle := styles.BaseStyle()
-	
+
 	content := p.permission.Description
 	content := p.permission.Description
 
 
 	// Use the cache for markdown rendering
 	// Use the cache for markdown rendering
 	renderedContent := p.GetOrSetMarkdown(p.permission.ID, func() (string, error) {
 	renderedContent := p.GetOrSetMarkdown(p.permission.ID, func() (string, error) {
-		r := styles.GetMarkdownRenderer(p.width-10)
+		r := styles.GetMarkdownRenderer(p.width - 10)
 		s, err := r.Render(content)
 		s, err := r.Render(content)
 		return styles.ForceReplaceBackgroundWithLipgloss(s, t.Background()), err
 		return styles.ForceReplaceBackgroundWithLipgloss(s, t.Background()), err
 	})
 	})
@@ -358,7 +358,7 @@ func (p *permissionDialogCmp) styleViewport() string {
 func (p *permissionDialogCmp) render() string {
 func (p *permissionDialogCmp) render() string {
 	t := theme.CurrentTheme()
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 	baseStyle := styles.BaseStyle()
-	
+
 	title := baseStyle.
 	title := baseStyle.
 		Bold(true).
 		Bold(true).
 		Width(p.width - 4).
 		Width(p.width - 4).

+ 1 - 1
internal/tui/components/dialog/quit.go

@@ -84,7 +84,7 @@ func (q *quitDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 func (q *quitDialogCmp) View() string {
 func (q *quitDialogCmp) View() string {
 	t := theme.CurrentTheme()
 	t := theme.CurrentTheme()
 	baseStyle := styles.BaseStyle()
 	baseStyle := styles.BaseStyle()
-	
+
 	yesStyle := baseStyle
 	yesStyle := baseStyle
 	noStyle := baseStyle
 	noStyle := baseStyle
 	spacerStyle := baseStyle.Background(t.Background())
 	spacerStyle := baseStyle.Background(t.Background())

+ 1 - 1
internal/tui/components/logs/details.go

@@ -96,7 +96,7 @@ func (i *detailCmp) updateContent() {
 		valueStyle := lipgloss.NewStyle().Foreground(t.Text())
 		valueStyle := lipgloss.NewStyle().Foreground(t.Text())
 
 
 		for key, value := range i.currentLog.Attributes {
 		for key, value := range i.currentLog.Attributes {
-			attrLine := fmt.Sprintf("%s: %s", 
+			attrLine := fmt.Sprintf("%s: %s",
 				keyStyle.Render(key),
 				keyStyle.Render(key),
 				valueStyle.Render(value),
 				valueStyle.Render(value),
 			)
 			)

+ 2 - 2
internal/tui/layout/container.go

@@ -31,7 +31,7 @@ type container struct {
 	borderBottom bool
 	borderBottom bool
 	borderLeft   bool
 	borderLeft   bool
 	borderStyle  lipgloss.Border
 	borderStyle  lipgloss.Border
-	
+
 	focused bool // Track focus state
 	focused bool // Track focus state
 }
 }
 
 
@@ -69,7 +69,7 @@ func (c *container) View() string {
 			width--
 			width--
 		}
 		}
 		style = style.Border(c.borderStyle, c.borderTop, c.borderRight, c.borderBottom, c.borderLeft)
 		style = style.Border(c.borderStyle, c.borderTop, c.borderRight, c.borderBottom, c.borderLeft)
-		
+
 		// Use primary color for border if focused
 		// Use primary color for border if focused
 		if c.focused {
 		if c.focused {
 			style = style.BorderBackground(t.Background()).BorderForeground(t.Primary())
 			style = style.BorderBackground(t.Background()).BorderForeground(t.Primary())

+ 2 - 2
internal/tui/page/logs.go

@@ -196,7 +196,7 @@ func (p *logsPage) Init() tea.Cmd {
 	var cmds []tea.Cmd
 	var cmds []tea.Cmd
 	cmds = append(cmds, p.table.Init())
 	cmds = append(cmds, p.table.Init())
 	cmds = append(cmds, p.details.Init())
 	cmds = append(cmds, p.details.Init())
-	
+
 	// Send a key down and then key up to select the first row
 	// Send a key down and then key up to select the first row
 	// This ensures the details pane is populated when returning to the logs page
 	// This ensures the details pane is populated when returning to the logs page
 	cmds = append(cmds, func() tea.Msg {
 	cmds = append(cmds, func() tea.Msg {
@@ -205,7 +205,7 @@ func (p *logsPage) Init() tea.Cmd {
 	cmds = append(cmds, func() tea.Msg {
 	cmds = append(cmds, func() tea.Msg {
 		return tea.KeyMsg{Type: tea.KeyUp}
 		return tea.KeyMsg{Type: tea.KeyUp}
 	})
 	})
-	
+
 	return tea.Batch(cmds...)
 	return tea.Batch(cmds...)
 }
 }
 
 

+ 1 - 1
internal/tui/theme/catppuccin.go

@@ -245,4 +245,4 @@ func NewCatppuccinTheme() *CatppuccinTheme {
 func init() {
 func init() {
 	// Register the Catppuccin theme with the theme manager
 	// Register the Catppuccin theme with the theme manager
 	RegisterTheme("catppuccin", NewCatppuccinTheme())
 	RegisterTheme("catppuccin", NewCatppuccinTheme())
-}
+}

+ 1 - 1
internal/tui/theme/dracula.go

@@ -271,4 +271,4 @@ func NewDraculaTheme() *DraculaTheme {
 func init() {
 func init() {
 	// Register the Dracula theme with the theme manager
 	// Register the Dracula theme with the theme manager
 	RegisterTheme("dracula", NewDraculaTheme())
 	RegisterTheme("dracula", NewDraculaTheme())
-}
+}

+ 15 - 15
internal/tui/theme/flexoki.go

@@ -7,20 +7,20 @@ import (
 // Flexoki color palette constants
 // Flexoki color palette constants
 const (
 const (
 	// Base colors
 	// Base colors
-	flexokiPaper    = "#FFFCF0" // Paper (lightest)
-	flexokiBase50   = "#F2F0E5" // bg-2 (light)
-	flexokiBase100  = "#E6E4D9" // ui (light)
-	flexokiBase150  = "#DAD8CE" // ui-2 (light)
-	flexokiBase200  = "#CECDC3" // ui-3 (light)
-	flexokiBase300  = "#B7B5AC" // tx-3 (light)
-	flexokiBase500  = "#878580" // tx-2 (light)
-	flexokiBase600  = "#6F6E69" // tx (light)
-	flexokiBase700  = "#575653" // tx-3 (dark)
-	flexokiBase800  = "#403E3C" // ui-3 (dark)
-	flexokiBase850  = "#343331" // ui-2 (dark)
-	flexokiBase900  = "#282726" // ui (dark)
-	flexokiBase950  = "#1C1B1A" // bg-2 (dark)
-	flexokiBlack    = "#100F0F" // bg (darkest)
+	flexokiPaper   = "#FFFCF0" // Paper (lightest)
+	flexokiBase50  = "#F2F0E5" // bg-2 (light)
+	flexokiBase100 = "#E6E4D9" // ui (light)
+	flexokiBase150 = "#DAD8CE" // ui-2 (light)
+	flexokiBase200 = "#CECDC3" // ui-3 (light)
+	flexokiBase300 = "#B7B5AC" // tx-3 (light)
+	flexokiBase500 = "#878580" // tx-2 (light)
+	flexokiBase600 = "#6F6E69" // tx (light)
+	flexokiBase700 = "#575653" // tx-3 (dark)
+	flexokiBase800 = "#403E3C" // ui-3 (dark)
+	flexokiBase850 = "#343331" // ui-2 (dark)
+	flexokiBase900 = "#282726" // ui (dark)
+	flexokiBase950 = "#1C1B1A" // bg-2 (dark)
+	flexokiBlack   = "#100F0F" // bg (darkest)
 
 
 	// Accent colors - Light theme (600)
 	// Accent colors - Light theme (600)
 	flexokiRed600     = "#AF3029"
 	flexokiRed600     = "#AF3029"
@@ -279,4 +279,4 @@ func NewFlexokiTheme() *FlexokiTheme {
 func init() {
 func init() {
 	// Register the Flexoki theme with the theme manager
 	// Register the Flexoki theme with the theme manager
 	RegisterTheme("flexoki", NewFlexokiTheme())
 	RegisterTheme("flexoki", NewFlexokiTheme())
-}
+}

+ 5 - 5
internal/tui/theme/gruvbox.go

@@ -173,11 +173,11 @@ func NewGruvboxTheme() *GruvboxTheme {
 		Light: gruvboxLightRedBright,
 		Light: gruvboxLightRedBright,
 	}
 	}
 	theme.DiffAddedBgColor = lipgloss.AdaptiveColor{
 	theme.DiffAddedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#3C4C3C",  // Darker green background
+		Dark:  "#3C4C3C", // Darker green background
 		Light: "#E8F5E9", // Light green background
 		Light: "#E8F5E9", // Light green background
 	}
 	}
 	theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{
 	theme.DiffRemovedBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#4C3C3C",  // Darker red background
+		Dark:  "#4C3C3C", // Darker red background
 		Light: "#FFEBEE", // Light red background
 		Light: "#FFEBEE", // Light red background
 	}
 	}
 	theme.DiffContextBgColor = lipgloss.AdaptiveColor{
 	theme.DiffContextBgColor = lipgloss.AdaptiveColor{
@@ -189,11 +189,11 @@ func NewGruvboxTheme() *GruvboxTheme {
 		Light: gruvboxLightFg4,
 		Light: gruvboxLightFg4,
 	}
 	}
 	theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{
 	theme.DiffAddedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#32432F",   // Slightly darker green
+		Dark:  "#32432F", // Slightly darker green
 		Light: "#C8E6C9", // Light green
 		Light: "#C8E6C9", // Light green
 	}
 	}
 	theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{
 	theme.DiffRemovedLineNumberBgColor = lipgloss.AdaptiveColor{
-		Dark:  "#43322F",   // Slightly darker red
+		Dark:  "#43322F", // Slightly darker red
 		Light: "#FFCDD2", // Light red
 		Light: "#FFCDD2", // Light red
 	}
 	}
 
 
@@ -299,4 +299,4 @@ func NewGruvboxTheme() *GruvboxTheme {
 func init() {
 func init() {
 	// Register the Gruvbox theme with the theme manager
 	// Register the Gruvbox theme with the theme manager
 	RegisterTheme("gruvbox", NewGruvboxTheme())
 	RegisterTheme("gruvbox", NewGruvboxTheme())
-}
+}

+ 1 - 1
internal/tui/theme/monokai.go

@@ -270,4 +270,4 @@ func NewMonokaiProTheme() *MonokaiProTheme {
 func init() {
 func init() {
 	// Register the Monokai Pro theme with the theme manager
 	// Register the Monokai Pro theme with the theme manager
 	RegisterTheme("monokai", NewMonokaiProTheme())
 	RegisterTheme("monokai", NewMonokaiProTheme())
-}
+}

+ 1 - 1
internal/tui/theme/onedark.go

@@ -271,4 +271,4 @@ func NewOneDarkTheme() *OneDarkTheme {
 func init() {
 func init() {
 	// Register the One Dark theme with the theme manager
 	// Register the One Dark theme with the theme manager
 	RegisterTheme("onedark", NewOneDarkTheme())
 	RegisterTheme("onedark", NewOneDarkTheme())
-}
+}

+ 0 - 1
internal/tui/theme/opencode.go

@@ -274,4 +274,3 @@ func init() {
 	// Register the OpenCode theme with the theme manager
 	// Register the OpenCode theme with the theme manager
 	RegisterTheme("opencode", NewOpenCodeTheme())
 	RegisterTheme("opencode", NewOpenCodeTheme())
 }
 }
-

+ 92 - 84
internal/tui/theme/theme.go

@@ -83,25 +83,25 @@ type Theme interface {
 // that can be embedded in concrete theme implementations.
 // that can be embedded in concrete theme implementations.
 type BaseTheme struct {
 type BaseTheme struct {
 	// Base colors
 	// Base colors
-	PrimaryColor       lipgloss.AdaptiveColor
-	SecondaryColor     lipgloss.AdaptiveColor
-	AccentColor        lipgloss.AdaptiveColor
+	PrimaryColor   lipgloss.AdaptiveColor
+	SecondaryColor lipgloss.AdaptiveColor
+	AccentColor    lipgloss.AdaptiveColor
 
 
 	// Status colors
 	// Status colors
-	ErrorColor         lipgloss.AdaptiveColor
-	WarningColor       lipgloss.AdaptiveColor
-	SuccessColor       lipgloss.AdaptiveColor
-	InfoColor          lipgloss.AdaptiveColor
+	ErrorColor   lipgloss.AdaptiveColor
+	WarningColor lipgloss.AdaptiveColor
+	SuccessColor lipgloss.AdaptiveColor
+	InfoColor    lipgloss.AdaptiveColor
 
 
 	// Text colors
 	// Text colors
-	TextColor          lipgloss.AdaptiveColor
-	TextMutedColor     lipgloss.AdaptiveColor
+	TextColor           lipgloss.AdaptiveColor
+	TextMutedColor      lipgloss.AdaptiveColor
 	TextEmphasizedColor lipgloss.AdaptiveColor
 	TextEmphasizedColor lipgloss.AdaptiveColor
 
 
 	// Background colors
 	// Background colors
-	BackgroundColor    lipgloss.AdaptiveColor
+	BackgroundColor          lipgloss.AdaptiveColor
 	BackgroundSecondaryColor lipgloss.AdaptiveColor
 	BackgroundSecondaryColor lipgloss.AdaptiveColor
-	BackgroundDarkerColor lipgloss.AdaptiveColor
+	BackgroundDarkerColor    lipgloss.AdaptiveColor
 
 
 	// Border colors
 	// Border colors
 	BorderNormalColor  lipgloss.AdaptiveColor
 	BorderNormalColor  lipgloss.AdaptiveColor
@@ -109,105 +109,113 @@ type BaseTheme struct {
 	BorderDimColor     lipgloss.AdaptiveColor
 	BorderDimColor     lipgloss.AdaptiveColor
 
 
 	// Diff view colors
 	// Diff view colors
-	DiffAddedColor     lipgloss.AdaptiveColor
-	DiffRemovedColor   lipgloss.AdaptiveColor
-	DiffContextColor   lipgloss.AdaptiveColor
-	DiffHunkHeaderColor lipgloss.AdaptiveColor
-	DiffHighlightAddedColor lipgloss.AdaptiveColor
-	DiffHighlightRemovedColor lipgloss.AdaptiveColor
-	DiffAddedBgColor   lipgloss.AdaptiveColor
-	DiffRemovedBgColor lipgloss.AdaptiveColor
-	DiffContextBgColor lipgloss.AdaptiveColor
-	DiffLineNumberColor lipgloss.AdaptiveColor
-	DiffAddedLineNumberBgColor lipgloss.AdaptiveColor
+	DiffAddedColor               lipgloss.AdaptiveColor
+	DiffRemovedColor             lipgloss.AdaptiveColor
+	DiffContextColor             lipgloss.AdaptiveColor
+	DiffHunkHeaderColor          lipgloss.AdaptiveColor
+	DiffHighlightAddedColor      lipgloss.AdaptiveColor
+	DiffHighlightRemovedColor    lipgloss.AdaptiveColor
+	DiffAddedBgColor             lipgloss.AdaptiveColor
+	DiffRemovedBgColor           lipgloss.AdaptiveColor
+	DiffContextBgColor           lipgloss.AdaptiveColor
+	DiffLineNumberColor          lipgloss.AdaptiveColor
+	DiffAddedLineNumberBgColor   lipgloss.AdaptiveColor
 	DiffRemovedLineNumberBgColor lipgloss.AdaptiveColor
 	DiffRemovedLineNumberBgColor lipgloss.AdaptiveColor
 
 
 	// Markdown colors
 	// Markdown colors
-	MarkdownTextColor  lipgloss.AdaptiveColor
-	MarkdownHeadingColor lipgloss.AdaptiveColor
-	MarkdownLinkColor  lipgloss.AdaptiveColor
-	MarkdownLinkTextColor lipgloss.AdaptiveColor
-	MarkdownCodeColor  lipgloss.AdaptiveColor
-	MarkdownBlockQuoteColor lipgloss.AdaptiveColor
-	MarkdownEmphColor  lipgloss.AdaptiveColor
-	MarkdownStrongColor lipgloss.AdaptiveColor
-	MarkdownHorizontalRuleColor lipgloss.AdaptiveColor
-	MarkdownListItemColor lipgloss.AdaptiveColor
+	MarkdownTextColor            lipgloss.AdaptiveColor
+	MarkdownHeadingColor         lipgloss.AdaptiveColor
+	MarkdownLinkColor            lipgloss.AdaptiveColor
+	MarkdownLinkTextColor        lipgloss.AdaptiveColor
+	MarkdownCodeColor            lipgloss.AdaptiveColor
+	MarkdownBlockQuoteColor      lipgloss.AdaptiveColor
+	MarkdownEmphColor            lipgloss.AdaptiveColor
+	MarkdownStrongColor          lipgloss.AdaptiveColor
+	MarkdownHorizontalRuleColor  lipgloss.AdaptiveColor
+	MarkdownListItemColor        lipgloss.AdaptiveColor
 	MarkdownListEnumerationColor lipgloss.AdaptiveColor
 	MarkdownListEnumerationColor lipgloss.AdaptiveColor
-	MarkdownImageColor lipgloss.AdaptiveColor
-	MarkdownImageTextColor lipgloss.AdaptiveColor
-	MarkdownCodeBlockColor lipgloss.AdaptiveColor
+	MarkdownImageColor           lipgloss.AdaptiveColor
+	MarkdownImageTextColor       lipgloss.AdaptiveColor
+	MarkdownCodeBlockColor       lipgloss.AdaptiveColor
 
 
 	// Syntax highlighting colors
 	// Syntax highlighting colors
-	SyntaxCommentColor lipgloss.AdaptiveColor
-	SyntaxKeywordColor lipgloss.AdaptiveColor
-	SyntaxFunctionColor lipgloss.AdaptiveColor
-	SyntaxVariableColor lipgloss.AdaptiveColor
-	SyntaxStringColor  lipgloss.AdaptiveColor
-	SyntaxNumberColor  lipgloss.AdaptiveColor
-	SyntaxTypeColor    lipgloss.AdaptiveColor
-	SyntaxOperatorColor lipgloss.AdaptiveColor
+	SyntaxCommentColor     lipgloss.AdaptiveColor
+	SyntaxKeywordColor     lipgloss.AdaptiveColor
+	SyntaxFunctionColor    lipgloss.AdaptiveColor
+	SyntaxVariableColor    lipgloss.AdaptiveColor
+	SyntaxStringColor      lipgloss.AdaptiveColor
+	SyntaxNumberColor      lipgloss.AdaptiveColor
+	SyntaxTypeColor        lipgloss.AdaptiveColor
+	SyntaxOperatorColor    lipgloss.AdaptiveColor
 	SyntaxPunctuationColor lipgloss.AdaptiveColor
 	SyntaxPunctuationColor lipgloss.AdaptiveColor
 }
 }
 
 
 // Implement the Theme interface for BaseTheme
 // Implement the Theme interface for BaseTheme
-func (t *BaseTheme) Primary() lipgloss.AdaptiveColor { return t.PrimaryColor }
+func (t *BaseTheme) Primary() lipgloss.AdaptiveColor   { return t.PrimaryColor }
 func (t *BaseTheme) Secondary() lipgloss.AdaptiveColor { return t.SecondaryColor }
 func (t *BaseTheme) Secondary() lipgloss.AdaptiveColor { return t.SecondaryColor }
-func (t *BaseTheme) Accent() lipgloss.AdaptiveColor { return t.AccentColor }
+func (t *BaseTheme) Accent() lipgloss.AdaptiveColor    { return t.AccentColor }
 
 
-func (t *BaseTheme) Error() lipgloss.AdaptiveColor { return t.ErrorColor }
+func (t *BaseTheme) Error() lipgloss.AdaptiveColor   { return t.ErrorColor }
 func (t *BaseTheme) Warning() lipgloss.AdaptiveColor { return t.WarningColor }
 func (t *BaseTheme) Warning() lipgloss.AdaptiveColor { return t.WarningColor }
 func (t *BaseTheme) Success() lipgloss.AdaptiveColor { return t.SuccessColor }
 func (t *BaseTheme) Success() lipgloss.AdaptiveColor { return t.SuccessColor }
-func (t *BaseTheme) Info() lipgloss.AdaptiveColor { return t.InfoColor }
+func (t *BaseTheme) Info() lipgloss.AdaptiveColor    { return t.InfoColor }
 
 
-func (t *BaseTheme) Text() lipgloss.AdaptiveColor { return t.TextColor }
-func (t *BaseTheme) TextMuted() lipgloss.AdaptiveColor { return t.TextMutedColor }
+func (t *BaseTheme) Text() lipgloss.AdaptiveColor           { return t.TextColor }
+func (t *BaseTheme) TextMuted() lipgloss.AdaptiveColor      { return t.TextMutedColor }
 func (t *BaseTheme) TextEmphasized() lipgloss.AdaptiveColor { return t.TextEmphasizedColor }
 func (t *BaseTheme) TextEmphasized() lipgloss.AdaptiveColor { return t.TextEmphasizedColor }
 
 
-func (t *BaseTheme) Background() lipgloss.AdaptiveColor { return t.BackgroundColor }
+func (t *BaseTheme) Background() lipgloss.AdaptiveColor          { return t.BackgroundColor }
 func (t *BaseTheme) BackgroundSecondary() lipgloss.AdaptiveColor { return t.BackgroundSecondaryColor }
 func (t *BaseTheme) BackgroundSecondary() lipgloss.AdaptiveColor { return t.BackgroundSecondaryColor }
-func (t *BaseTheme) BackgroundDarker() lipgloss.AdaptiveColor { return t.BackgroundDarkerColor }
+func (t *BaseTheme) BackgroundDarker() lipgloss.AdaptiveColor    { return t.BackgroundDarkerColor }
 
 
-func (t *BaseTheme) BorderNormal() lipgloss.AdaptiveColor { return t.BorderNormalColor }
+func (t *BaseTheme) BorderNormal() lipgloss.AdaptiveColor  { return t.BorderNormalColor }
 func (t *BaseTheme) BorderFocused() lipgloss.AdaptiveColor { return t.BorderFocusedColor }
 func (t *BaseTheme) BorderFocused() lipgloss.AdaptiveColor { return t.BorderFocusedColor }
-func (t *BaseTheme) BorderDim() lipgloss.AdaptiveColor { return t.BorderDimColor }
+func (t *BaseTheme) BorderDim() lipgloss.AdaptiveColor     { return t.BorderDimColor }
 
 
-func (t *BaseTheme) DiffAdded() lipgloss.AdaptiveColor { return t.DiffAddedColor }
-func (t *BaseTheme) DiffRemoved() lipgloss.AdaptiveColor { return t.DiffRemovedColor }
-func (t *BaseTheme) DiffContext() lipgloss.AdaptiveColor { return t.DiffContextColor }
-func (t *BaseTheme) DiffHunkHeader() lipgloss.AdaptiveColor { return t.DiffHunkHeaderColor }
-func (t *BaseTheme) DiffHighlightAdded() lipgloss.AdaptiveColor { return t.DiffHighlightAddedColor }
+func (t *BaseTheme) DiffAdded() lipgloss.AdaptiveColor            { return t.DiffAddedColor }
+func (t *BaseTheme) DiffRemoved() lipgloss.AdaptiveColor          { return t.DiffRemovedColor }
+func (t *BaseTheme) DiffContext() lipgloss.AdaptiveColor          { return t.DiffContextColor }
+func (t *BaseTheme) DiffHunkHeader() lipgloss.AdaptiveColor       { return t.DiffHunkHeaderColor }
+func (t *BaseTheme) DiffHighlightAdded() lipgloss.AdaptiveColor   { return t.DiffHighlightAddedColor }
 func (t *BaseTheme) DiffHighlightRemoved() lipgloss.AdaptiveColor { return t.DiffHighlightRemovedColor }
 func (t *BaseTheme) DiffHighlightRemoved() lipgloss.AdaptiveColor { return t.DiffHighlightRemovedColor }
-func (t *BaseTheme) DiffAddedBg() lipgloss.AdaptiveColor { return t.DiffAddedBgColor }
-func (t *BaseTheme) DiffRemovedBg() lipgloss.AdaptiveColor { return t.DiffRemovedBgColor }
-func (t *BaseTheme) DiffContextBg() lipgloss.AdaptiveColor { return t.DiffContextBgColor }
-func (t *BaseTheme) DiffLineNumber() lipgloss.AdaptiveColor { return t.DiffLineNumberColor }
-func (t *BaseTheme) DiffAddedLineNumberBg() lipgloss.AdaptiveColor { return t.DiffAddedLineNumberBgColor }
-func (t *BaseTheme) DiffRemovedLineNumberBg() lipgloss.AdaptiveColor { return t.DiffRemovedLineNumberBgColor }
-
-func (t *BaseTheme) MarkdownText() lipgloss.AdaptiveColor { return t.MarkdownTextColor }
-func (t *BaseTheme) MarkdownHeading() lipgloss.AdaptiveColor { return t.MarkdownHeadingColor }
-func (t *BaseTheme) MarkdownLink() lipgloss.AdaptiveColor { return t.MarkdownLinkColor }
-func (t *BaseTheme) MarkdownLinkText() lipgloss.AdaptiveColor { return t.MarkdownLinkTextColor }
-func (t *BaseTheme) MarkdownCode() lipgloss.AdaptiveColor { return t.MarkdownCodeColor }
+func (t *BaseTheme) DiffAddedBg() lipgloss.AdaptiveColor          { return t.DiffAddedBgColor }
+func (t *BaseTheme) DiffRemovedBg() lipgloss.AdaptiveColor        { return t.DiffRemovedBgColor }
+func (t *BaseTheme) DiffContextBg() lipgloss.AdaptiveColor        { return t.DiffContextBgColor }
+func (t *BaseTheme) DiffLineNumber() lipgloss.AdaptiveColor       { return t.DiffLineNumberColor }
+func (t *BaseTheme) DiffAddedLineNumberBg() lipgloss.AdaptiveColor {
+	return t.DiffAddedLineNumberBgColor
+}
+func (t *BaseTheme) DiffRemovedLineNumberBg() lipgloss.AdaptiveColor {
+	return t.DiffRemovedLineNumberBgColor
+}
+
+func (t *BaseTheme) MarkdownText() lipgloss.AdaptiveColor       { return t.MarkdownTextColor }
+func (t *BaseTheme) MarkdownHeading() lipgloss.AdaptiveColor    { return t.MarkdownHeadingColor }
+func (t *BaseTheme) MarkdownLink() lipgloss.AdaptiveColor       { return t.MarkdownLinkColor }
+func (t *BaseTheme) MarkdownLinkText() lipgloss.AdaptiveColor   { return t.MarkdownLinkTextColor }
+func (t *BaseTheme) MarkdownCode() lipgloss.AdaptiveColor       { return t.MarkdownCodeColor }
 func (t *BaseTheme) MarkdownBlockQuote() lipgloss.AdaptiveColor { return t.MarkdownBlockQuoteColor }
 func (t *BaseTheme) MarkdownBlockQuote() lipgloss.AdaptiveColor { return t.MarkdownBlockQuoteColor }
-func (t *BaseTheme) MarkdownEmph() lipgloss.AdaptiveColor { return t.MarkdownEmphColor }
-func (t *BaseTheme) MarkdownStrong() lipgloss.AdaptiveColor { return t.MarkdownStrongColor }
-func (t *BaseTheme) MarkdownHorizontalRule() lipgloss.AdaptiveColor { return t.MarkdownHorizontalRuleColor }
+func (t *BaseTheme) MarkdownEmph() lipgloss.AdaptiveColor       { return t.MarkdownEmphColor }
+func (t *BaseTheme) MarkdownStrong() lipgloss.AdaptiveColor     { return t.MarkdownStrongColor }
+func (t *BaseTheme) MarkdownHorizontalRule() lipgloss.AdaptiveColor {
+	return t.MarkdownHorizontalRuleColor
+}
 func (t *BaseTheme) MarkdownListItem() lipgloss.AdaptiveColor { return t.MarkdownListItemColor }
 func (t *BaseTheme) MarkdownListItem() lipgloss.AdaptiveColor { return t.MarkdownListItemColor }
-func (t *BaseTheme) MarkdownListEnumeration() lipgloss.AdaptiveColor { return t.MarkdownListEnumerationColor }
-func (t *BaseTheme) MarkdownImage() lipgloss.AdaptiveColor { return t.MarkdownImageColor }
+func (t *BaseTheme) MarkdownListEnumeration() lipgloss.AdaptiveColor {
+	return t.MarkdownListEnumerationColor
+}
+func (t *BaseTheme) MarkdownImage() lipgloss.AdaptiveColor     { return t.MarkdownImageColor }
 func (t *BaseTheme) MarkdownImageText() lipgloss.AdaptiveColor { return t.MarkdownImageTextColor }
 func (t *BaseTheme) MarkdownImageText() lipgloss.AdaptiveColor { return t.MarkdownImageTextColor }
 func (t *BaseTheme) MarkdownCodeBlock() lipgloss.AdaptiveColor { return t.MarkdownCodeBlockColor }
 func (t *BaseTheme) MarkdownCodeBlock() lipgloss.AdaptiveColor { return t.MarkdownCodeBlockColor }
 
 
-func (t *BaseTheme) SyntaxComment() lipgloss.AdaptiveColor { return t.SyntaxCommentColor }
-func (t *BaseTheme) SyntaxKeyword() lipgloss.AdaptiveColor { return t.SyntaxKeywordColor }
-func (t *BaseTheme) SyntaxFunction() lipgloss.AdaptiveColor { return t.SyntaxFunctionColor }
-func (t *BaseTheme) SyntaxVariable() lipgloss.AdaptiveColor { return t.SyntaxVariableColor }
-func (t *BaseTheme) SyntaxString() lipgloss.AdaptiveColor { return t.SyntaxStringColor }
-func (t *BaseTheme) SyntaxNumber() lipgloss.AdaptiveColor { return t.SyntaxNumberColor }
-func (t *BaseTheme) SyntaxType() lipgloss.AdaptiveColor { return t.SyntaxTypeColor }
-func (t *BaseTheme) SyntaxOperator() lipgloss.AdaptiveColor { return t.SyntaxOperatorColor }
+func (t *BaseTheme) SyntaxComment() lipgloss.AdaptiveColor     { return t.SyntaxCommentColor }
+func (t *BaseTheme) SyntaxKeyword() lipgloss.AdaptiveColor     { return t.SyntaxKeywordColor }
+func (t *BaseTheme) SyntaxFunction() lipgloss.AdaptiveColor    { return t.SyntaxFunctionColor }
+func (t *BaseTheme) SyntaxVariable() lipgloss.AdaptiveColor    { return t.SyntaxVariableColor }
+func (t *BaseTheme) SyntaxString() lipgloss.AdaptiveColor      { return t.SyntaxStringColor }
+func (t *BaseTheme) SyntaxNumber() lipgloss.AdaptiveColor      { return t.SyntaxNumberColor }
+func (t *BaseTheme) SyntaxType() lipgloss.AdaptiveColor        { return t.SyntaxTypeColor }
+func (t *BaseTheme) SyntaxOperator() lipgloss.AdaptiveColor    { return t.SyntaxOperatorColor }
 func (t *BaseTheme) SyntaxPunctuation() lipgloss.AdaptiveColor { return t.SyntaxPunctuationColor }
 func (t *BaseTheme) SyntaxPunctuation() lipgloss.AdaptiveColor { return t.SyntaxPunctuationColor }
 
 
 // ParseAdaptiveColor parses a color value from the config file into a lipgloss.AdaptiveColor.
 // ParseAdaptiveColor parses a color value from the config file into a lipgloss.AdaptiveColor.
@@ -254,4 +262,4 @@ func ParseAdaptiveColor(value any) (lipgloss.AdaptiveColor, error) {
 	}
 	}
 
 
 	return lipgloss.AdaptiveColor{}, fmt.Errorf("color must be either a hex string or an object with dark/light keys")
 	return lipgloss.AdaptiveColor{}, fmt.Errorf("color must be either a hex string or an object with dark/light keys")
-}
+}

+ 16 - 16
internal/tui/theme/theme_test.go

@@ -7,7 +7,7 @@ import (
 func TestThemeRegistration(t *testing.T) {
 func TestThemeRegistration(t *testing.T) {
 	// Get list of available themes
 	// Get list of available themes
 	availableThemes := AvailableThemes()
 	availableThemes := AvailableThemes()
-	
+
 	// Check if "catppuccin" theme is registered
 	// Check if "catppuccin" theme is registered
 	catppuccinFound := false
 	catppuccinFound := false
 	for _, themeName := range availableThemes {
 	for _, themeName := range availableThemes {
@@ -16,11 +16,11 @@ func TestThemeRegistration(t *testing.T) {
 			break
 			break
 		}
 		}
 	}
 	}
-	
+
 	if !catppuccinFound {
 	if !catppuccinFound {
 		t.Errorf("Catppuccin theme is not registered")
 		t.Errorf("Catppuccin theme is not registered")
 	}
 	}
-	
+
 	// Check if "gruvbox" theme is registered
 	// Check if "gruvbox" theme is registered
 	gruvboxFound := false
 	gruvboxFound := false
 	for _, themeName := range availableThemes {
 	for _, themeName := range availableThemes {
@@ -29,11 +29,11 @@ func TestThemeRegistration(t *testing.T) {
 			break
 			break
 		}
 		}
 	}
 	}
-	
+
 	if !gruvboxFound {
 	if !gruvboxFound {
 		t.Errorf("Gruvbox theme is not registered")
 		t.Errorf("Gruvbox theme is not registered")
 	}
 	}
-	
+
 	// Check if "monokai" theme is registered
 	// Check if "monokai" theme is registered
 	monokaiFound := false
 	monokaiFound := false
 	for _, themeName := range availableThemes {
 	for _, themeName := range availableThemes {
@@ -42,48 +42,48 @@ func TestThemeRegistration(t *testing.T) {
 			break
 			break
 		}
 		}
 	}
 	}
-	
+
 	if !monokaiFound {
 	if !monokaiFound {
 		t.Errorf("Monokai theme is not registered")
 		t.Errorf("Monokai theme is not registered")
 	}
 	}
-	
+
 	// Try to get the themes and make sure they're not nil
 	// Try to get the themes and make sure they're not nil
 	catppuccin := GetTheme("catppuccin")
 	catppuccin := GetTheme("catppuccin")
 	if catppuccin == nil {
 	if catppuccin == nil {
 		t.Errorf("Catppuccin theme is nil")
 		t.Errorf("Catppuccin theme is nil")
 	}
 	}
-	
+
 	gruvbox := GetTheme("gruvbox")
 	gruvbox := GetTheme("gruvbox")
 	if gruvbox == nil {
 	if gruvbox == nil {
 		t.Errorf("Gruvbox theme is nil")
 		t.Errorf("Gruvbox theme is nil")
 	}
 	}
-	
+
 	monokai := GetTheme("monokai")
 	monokai := GetTheme("monokai")
 	if monokai == nil {
 	if monokai == nil {
 		t.Errorf("Monokai theme is nil")
 		t.Errorf("Monokai theme is nil")
 	}
 	}
-	
+
 	// Test switching theme
 	// Test switching theme
 	originalTheme := CurrentThemeName()
 	originalTheme := CurrentThemeName()
-	
+
 	err := SetTheme("gruvbox")
 	err := SetTheme("gruvbox")
 	if err != nil {
 	if err != nil {
 		t.Errorf("Failed to set theme to gruvbox: %v", err)
 		t.Errorf("Failed to set theme to gruvbox: %v", err)
 	}
 	}
-	
+
 	if CurrentThemeName() != "gruvbox" {
 	if CurrentThemeName() != "gruvbox" {
 		t.Errorf("Theme not properly switched to gruvbox")
 		t.Errorf("Theme not properly switched to gruvbox")
 	}
 	}
-	
+
 	err = SetTheme("monokai")
 	err = SetTheme("monokai")
 	if err != nil {
 	if err != nil {
 		t.Errorf("Failed to set theme to monokai: %v", err)
 		t.Errorf("Failed to set theme to monokai: %v", err)
 	}
 	}
-	
+
 	if CurrentThemeName() != "monokai" {
 	if CurrentThemeName() != "monokai" {
 		t.Errorf("Theme not properly switched to monokai")
 		t.Errorf("Theme not properly switched to monokai")
 	}
 	}
-	
+
 	// Switch back to original theme
 	// Switch back to original theme
 	_ = SetTheme(originalTheme)
 	_ = SetTheme(originalTheme)
-}
+}

+ 1 - 1
internal/tui/theme/tokyonight.go

@@ -271,4 +271,4 @@ func NewTokyoNightTheme() *TokyoNightTheme {
 func init() {
 func init() {
 	// Register the Tokyo Night theme with the theme manager
 	// Register the Tokyo Night theme with the theme manager
 	RegisterTheme("tokyonight", NewTokyoNightTheme())
 	RegisterTheme("tokyonight", NewTokyoNightTheme())
-}
+}

+ 1 - 1
internal/tui/theme/tron.go

@@ -273,4 +273,4 @@ func NewTronTheme() *TronTheme {
 func init() {
 func init() {
 	// Register the Tron theme with the theme manager
 	// Register the Tron theme with the theme manager
 	RegisterTheme("tron", NewTronTheme())
 	RegisterTheme("tron", NewTronTheme())
-}
+}