From e4880ac5420c36f53de42f1b34449d3c3e81b3d4 Mon Sep 17 00:00:00 2001 From: Kujtim Hoxha Date: Fri, 6 Feb 2026 12:55:25 +0100 Subject: [PATCH] refactor: add Service getters for Config fields, migrate callers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add DataDirectory, Debug, DebugLSP, DisableAutoSummarize, Attribution, ContextPaths, SkillsPaths, Progress, DisableMetrics, SelectedModel, Agent, MCP, LSP, Permissions, ToolLsConfig, CompactMode, DiffMode, CompletionLimits, and more to Service. Migrate coordinator, app, cmd, and UI callers to use Service getters instead of direct Config field access. 🐾 Generated with Crush Assisted-by: Claude Opus 4.6 via Crush --- internal/agent/agent_tool.go | 6 +- internal/agent/agentic_fetch_tool.go | 8 +- internal/agent/coordinator.go | 50 +++++----- internal/app/app.go | 4 +- internal/app/lsp.go | 4 +- internal/cmd/logs.go | 2 +- internal/cmd/root.go | 14 +-- internal/config/service.go | 142 +++++++++++++++++++++++++++ internal/ui/model/header.go | 2 +- internal/ui/model/mcp.go | 2 +- internal/ui/model/sidebar.go | 2 +- internal/ui/model/ui.go | 8 +- 12 files changed, 193 insertions(+), 51 deletions(-) diff --git a/internal/agent/agent_tool.go b/internal/agent/agent_tool.go index 29566b1c5a00d00c1254a3f07cdcef71ba55d59e..ceda8a093a8925a3de67141eacef4e453a842d75 100644 --- a/internal/agent/agent_tool.go +++ b/internal/agent/agent_tool.go @@ -25,11 +25,11 @@ const ( ) func (c *coordinator) agentTool(ctx context.Context) (fantasy.AgentTool, error) { - agentCfg, ok := c.cfg.Agents[config.AgentTask] + agentCfg, ok := c.cfgSvc.Agents()[config.AgentTask] if !ok { return nil, errors.New("task agent not configured") } - prompt, err := taskPrompt(prompt.WithWorkingDir(c.cfg.WorkingDir())) + prompt, err := taskPrompt(prompt.WithWorkingDir(c.cfgSvc.WorkingDir())) if err != nil { return nil, err } @@ -67,7 +67,7 @@ func (c *coordinator) agentTool(ctx context.Context) (fantasy.AgentTool, error) maxTokens = model.ModelCfg.MaxTokens } - providerCfg, ok := c.cfg.Providers.Get(model.ModelCfg.Provider) + providerCfg, ok := c.cfgSvc.Config().Providers.Get(model.ModelCfg.Provider) if !ok { return fantasy.ToolResponse{}, errors.New("model provider not configured") } diff --git a/internal/agent/agentic_fetch_tool.go b/internal/agent/agentic_fetch_tool.go index 9bf592413b07c651171d10785104294da8fb39a3..574525da61e483690582ec0645dbd2305598590b 100644 --- a/internal/agent/agentic_fetch_tool.go +++ b/internal/agent/agentic_fetch_tool.go @@ -83,7 +83,7 @@ func (c *coordinator) agenticFetchTool(_ context.Context, client *http.Client) ( p, err := c.permissions.Request(ctx, permission.CreatePermissionRequest{ SessionID: validationResult.SessionID, - Path: c.cfg.WorkingDir(), + Path: c.cfgSvc.WorkingDir(), ToolCallID: call.ID, ToolName: tools.AgenticFetchToolName, Action: "fetch", @@ -98,7 +98,7 @@ func (c *coordinator) agenticFetchTool(_ context.Context, client *http.Client) ( return fantasy.ToolResponse{}, permission.ErrorPermissionDenied } - tmpDir, err := os.MkdirTemp(c.cfg.Options.DataDirectory, "crush-fetch-*") + tmpDir, err := os.MkdirTemp(c.cfgSvc.Config().Options.DataDirectory, "crush-fetch-*") if err != nil { return fantasy.NewTextErrorResponse(fmt.Sprintf("Failed to create temporary directory: %s", err)), nil } @@ -156,7 +156,7 @@ func (c *coordinator) agenticFetchTool(_ context.Context, client *http.Client) ( return fantasy.ToolResponse{}, fmt.Errorf("error building system prompt: %s", err) } - smallProviderCfg, ok := c.cfg.Providers.Get(small.ModelCfg.Provider) + smallProviderCfg, ok := c.cfgSvc.Config().Providers.Get(small.ModelCfg.Provider) if !ok { return fantasy.ToolResponse{}, errors.New("small model provider not configured") } @@ -177,7 +177,7 @@ func (c *coordinator) agenticFetchTool(_ context.Context, client *http.Client) ( SmallModel: small, SystemPromptPrefix: smallProviderCfg.SystemPromptPrefix, SystemPrompt: systemPrompt, - DisableAutoSummarize: c.cfg.Options.DisableAutoSummarize, + DisableAutoSummarize: c.cfgSvc.Config().Options.DisableAutoSummarize, IsYolo: c.permissions.SkipRequests(), Sessions: c.sessions, Messages: c.messages, diff --git a/internal/agent/coordinator.go b/internal/agent/coordinator.go index 83f5379081c47b06815e5e8b443c3a0b30f711f2..a6889e886a0df69b43a7e9c5c1215c03d42ad957 100644 --- a/internal/agent/coordinator.go +++ b/internal/agent/coordinator.go @@ -147,7 +147,7 @@ func (c *coordinator) Run(ctx context.Context, sessionID string, prompt string, attachments = filteredAttachments } - providerCfg, ok := c.cfg.Providers.Get(model.ModelCfg.Provider) + providerCfg, ok := c.cfgSvc.Config().Providers.Get(model.ModelCfg.Provider) if !ok { return nil, errors.New("model provider not configured") } @@ -360,14 +360,14 @@ func (c *coordinator) buildAgent(ctx context.Context, prompt *prompt.Prompt, age return nil, err } - largeProviderCfg, _ := c.cfg.Providers.Get(large.ModelCfg.Provider) + largeProviderCfg, _ := c.cfgSvc.Config().Providers.Get(large.ModelCfg.Provider) result := NewSessionAgent(SessionAgentOptions{ large, small, largeProviderCfg.SystemPromptPrefix, "", isSubAgent, - c.cfg.Options.DisableAutoSummarize, + c.cfgSvc.DisableAutoSummarize(), c.permissions.SkipRequests(), c.sessions, c.messages, @@ -415,14 +415,14 @@ func (c *coordinator) buildTools(ctx context.Context, agent config.Agent) ([]fan // Get the model name for the agent modelName := "" - if modelCfg, ok := c.cfg.Models[agent.Model]; ok { + if modelCfg, ok := c.cfgSvc.Config().Models[agent.Model]; ok { if model := c.cfgSvc.GetModel(modelCfg.Provider, modelCfg.Model); model != nil { modelName = model.Name } } allTools = append(allTools, - tools.NewBashTool(c.permissions, c.cfgSvc.WorkingDir(), c.cfg.Options.Attribution, modelName), + tools.NewBashTool(c.permissions, c.cfgSvc.WorkingDir(), c.cfgSvc.Attribution(), modelName), tools.NewJobOutputTool(), tools.NewJobKillTool(), tools.NewDownloadTool(c.permissions, c.cfgSvc.WorkingDir(), nil), @@ -431,10 +431,10 @@ func (c *coordinator) buildTools(ctx context.Context, agent config.Agent) ([]fan tools.NewFetchTool(c.permissions, c.cfgSvc.WorkingDir(), nil), tools.NewGlobTool(c.cfgSvc.WorkingDir()), tools.NewGrepTool(c.cfgSvc.WorkingDir()), - tools.NewLsTool(c.permissions, c.cfgSvc.WorkingDir(), c.cfg.Tools.Ls), + tools.NewLsTool(c.permissions, c.cfgSvc.WorkingDir(), c.cfgSvc.ToolLsConfig()), tools.NewSourcegraphTool(nil), tools.NewTodosTool(c.sessions), - tools.NewViewTool(c.lspClients, c.permissions, c.filetracker, c.cfgSvc.WorkingDir(), c.cfg.Options.SkillsPaths...), + tools.NewViewTool(c.lspClients, c.permissions, c.filetracker, c.cfgSvc.WorkingDir(), c.cfgSvc.SkillsPaths()...), tools.NewWriteTool(c.lspClients, c.permissions, c.history, c.filetracker, c.cfgSvc.WorkingDir()), ) @@ -479,16 +479,16 @@ func (c *coordinator) buildTools(ctx context.Context, agent config.Agent) ([]fan // TODO: when we support multiple agents we need to change this so that we pass in the agent specific model config func (c *coordinator) buildAgentModels(ctx context.Context, isSubAgent bool) (Model, Model, error) { - largeModelCfg, ok := c.cfg.Models[config.SelectedModelTypeLarge] + largeModelCfg, ok := c.cfgSvc.Config().Models[config.SelectedModelTypeLarge] if !ok { return Model{}, Model{}, errors.New("large model not selected") } - smallModelCfg, ok := c.cfg.Models[config.SelectedModelTypeSmall] + smallModelCfg, ok := c.cfgSvc.Config().Models[config.SelectedModelTypeSmall] if !ok { return Model{}, Model{}, errors.New("small model not selected") } - largeProviderCfg, ok := c.cfg.Providers.Get(largeModelCfg.Provider) + largeProviderCfg, ok := c.cfgSvc.Config().Providers.Get(largeModelCfg.Provider) if !ok { return Model{}, Model{}, errors.New("large model provider not configured") } @@ -498,7 +498,7 @@ func (c *coordinator) buildAgentModels(ctx context.Context, isSubAgent bool) (Mo return Model{}, Model{}, err } - smallProviderCfg, ok := c.cfg.Providers.Get(smallModelCfg.Provider) + smallProviderCfg, ok := c.cfgSvc.Config().Providers.Get(smallModelCfg.Provider) if !ok { return Model{}, Model{}, errors.New("large model provider not configured") } @@ -581,7 +581,7 @@ func (c *coordinator) buildAnthropicProvider(baseURL, apiKey string, headers map opts = append(opts, anthropic.WithBaseURL(baseURL)) } - if c.cfg.Options.Debug { + if c.cfgSvc.Debug() { httpClient := log.NewHTTPClient() opts = append(opts, anthropic.WithHTTPClient(httpClient)) } @@ -593,7 +593,7 @@ func (c *coordinator) buildOpenaiProvider(baseURL, apiKey string, headers map[st openai.WithAPIKey(apiKey), openai.WithUseResponsesAPI(), } - if c.cfg.Options.Debug { + if c.cfgSvc.Debug() { httpClient := log.NewHTTPClient() opts = append(opts, openai.WithHTTPClient(httpClient)) } @@ -610,7 +610,7 @@ func (c *coordinator) buildOpenrouterProvider(_, apiKey string, headers map[stri opts := []openrouter.Option{ openrouter.WithAPIKey(apiKey), } - if c.cfg.Options.Debug { + if c.cfgSvc.Debug() { httpClient := log.NewHTTPClient() opts = append(opts, openrouter.WithHTTPClient(httpClient)) } @@ -624,7 +624,7 @@ func (c *coordinator) buildVercelProvider(_, apiKey string, headers map[string]s opts := []vercel.Option{ vercel.WithAPIKey(apiKey), } - if c.cfg.Options.Debug { + if c.cfgSvc.Debug() { httpClient := log.NewHTTPClient() opts = append(opts, vercel.WithHTTPClient(httpClient)) } @@ -644,8 +644,8 @@ func (c *coordinator) buildOpenaiCompatProvider(baseURL, apiKey string, headers var httpClient *http.Client if providerID == string(catwalk.InferenceProviderCopilot) { opts = append(opts, openaicompat.WithUseResponsesAPI()) - httpClient = copilot.NewClient(isSubAgent, c.cfg.Options.Debug) - } else if c.cfg.Options.Debug { + httpClient = copilot.NewClient(isSubAgent, c.cfgSvc.Debug()) + } else if c.cfgSvc.Debug() { httpClient = log.NewHTTPClient() } if httpClient != nil { @@ -669,7 +669,7 @@ func (c *coordinator) buildAzureProvider(baseURL, apiKey string, headers map[str azure.WithAPIKey(apiKey), azure.WithUseResponsesAPI(), } - if c.cfg.Options.Debug { + if c.cfgSvc.Debug() { httpClient := log.NewHTTPClient() opts = append(opts, azure.WithHTTPClient(httpClient)) } @@ -688,7 +688,7 @@ func (c *coordinator) buildAzureProvider(baseURL, apiKey string, headers map[str func (c *coordinator) buildBedrockProvider(headers map[string]string) (fantasy.Provider, error) { var opts []bedrock.Option - if c.cfg.Options.Debug { + if c.cfgSvc.Debug() { httpClient := log.NewHTTPClient() opts = append(opts, bedrock.WithHTTPClient(httpClient)) } @@ -707,7 +707,7 @@ func (c *coordinator) buildGoogleProvider(baseURL, apiKey string, headers map[st google.WithBaseURL(baseURL), google.WithGeminiAPIKey(apiKey), } - if c.cfg.Options.Debug { + if c.cfgSvc.Debug() { httpClient := log.NewHTTPClient() opts = append(opts, google.WithHTTPClient(httpClient)) } @@ -719,7 +719,7 @@ func (c *coordinator) buildGoogleProvider(baseURL, apiKey string, headers map[st func (c *coordinator) buildGoogleVertexProvider(headers map[string]string, options map[string]string) (fantasy.Provider, error) { opts := []google.Option{} - if c.cfg.Options.Debug { + if c.cfgSvc.Debug() { httpClient := log.NewHTTPClient() opts = append(opts, google.WithHTTPClient(httpClient)) } @@ -740,7 +740,7 @@ func (c *coordinator) buildHyperProvider(baseURL, apiKey string) (fantasy.Provid hyper.WithBaseURL(baseURL), hyper.WithAPIKey(apiKey), } - if c.cfg.Options.Debug { + if c.cfgSvc.Debug() { httpClient := log.NewHTTPClient() opts = append(opts, hyper.WithHTTPClient(httpClient)) } @@ -859,7 +859,7 @@ func (c *coordinator) UpdateModels(ctx context.Context) error { } c.currentAgent.SetModels(large, small) - agentCfg, ok := c.cfg.Agents[config.AgentCoder] + agentCfg, ok := c.cfgSvc.Agents()[config.AgentCoder] if !ok { return errors.New("coder agent not configured") } @@ -881,7 +881,7 @@ func (c *coordinator) QueuedPromptsList(sessionID string) []string { } func (c *coordinator) Summarize(ctx context.Context, sessionID string) error { - providerCfg, ok := c.cfg.Providers.Get(c.currentAgent.Model().ModelCfg.Provider) + providerCfg, ok := c.cfgSvc.Config().Providers.Get(c.currentAgent.Model().ModelCfg.Provider) if !ok { return errors.New("model provider not configured") } @@ -912,7 +912,7 @@ func (c *coordinator) refreshApiKeyTemplate(ctx context.Context, providerCfg con } providerCfg.APIKey = newAPIKey - c.cfg.Providers.Set(providerCfg.ID, providerCfg) + c.cfgSvc.Config().Providers.Set(providerCfg.ID, providerCfg) if err := c.UpdateModels(ctx); err != nil { return err diff --git a/internal/app/app.go b/internal/app/app.go index 18bd3bed16ba3eb3f107e4c9d5dc98dbaead7f8c..bbebcbfea9d03ca97fcf71094b420bd181ee9516 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -165,7 +165,7 @@ func (app *App) RunNonInteractive(ctx context.Context, output io.Writer, prompt, } stderrTTY = term.IsTerminal(os.Stderr.Fd()) stdinTTY = term.IsTerminal(os.Stdin.Fd()) - progress = app.config.Options.Progress == nil || *app.config.Options.Progress + progress = app.configService.Progress() == nil || *app.configService.Progress() if !hideSpinner && stderrTTY { t := styles.DefaultStyles() @@ -463,7 +463,7 @@ func setupSubscriber[T any]( } func (app *App) InitCoderAgent(ctx context.Context) error { - coderAgentCfg := app.config.Agents[config.AgentCoder] + coderAgentCfg := app.configService.Agents()[config.AgentCoder] if coderAgentCfg.ID == "" { return fmt.Errorf("coder agent configuration is missing") } diff --git a/internal/app/lsp.go b/internal/app/lsp.go index df6d8d86de63edee8c59c185e1938136d2785fcb..a1c8c8044327a4192ae1881ed14da06c0d98d6eb 100644 --- a/internal/app/lsp.go +++ b/internal/app/lsp.go @@ -63,7 +63,7 @@ func (app *App) initLSPClients(ctx context.Context) { var wg sync.WaitGroup for name, server := range filtered { - if app.config.Options.AutoLSP != nil && !*app.config.Options.AutoLSP && !slices.Contains(userConfiguredLSPs, name) { + if app.configService.AutoLSP() != nil && !*app.configService.AutoLSP() && !slices.Contains(userConfiguredLSPs, name) { slog.Debug("Ignoring non user-define LSP client due to AutoLSP being disabled", "name", name) continue } @@ -114,7 +114,7 @@ func (app *App) createAndStartLSPClient(ctx context.Context, name string, config updateLSPState(name, lsp.StateStarting, nil, nil, 0) // Create LSP client. - lspClient, err := lsp.New(ctx, name, config, app.configService.Resolver(), app.config.Options.DebugLSP) + lspClient, err := lsp.New(ctx, name, config, app.configService.Resolver(), app.configService.DebugLSP()) if err != nil { if !userConfigured { slog.Warn("Default LSP config skipped due to error", "name", name, "error", err) diff --git a/internal/cmd/logs.go b/internal/cmd/logs.go index 3de9a88a96600aa6f14c76c0be4f11b24bc226dd..5c499dbd0d53006b87cf23ffd41cfaf97d3ad46e 100644 --- a/internal/cmd/logs.go +++ b/internal/cmd/logs.go @@ -55,7 +55,7 @@ var logsCmd = &cobra.Command{ if err != nil { return fmt.Errorf("failed to load configuration: %v", err) } - logsFile := filepath.Join(cfg.Config().Options.DataDirectory, "logs", "crush.log") + logsFile := filepath.Join(cfg.DataDirectory(), "logs", "crush.log") _, err = os.Stat(logsFile) if os.IsNotExist(err) { log.Warn("Looks like you are not in a crush project. No logs found.") diff --git a/internal/cmd/root.go b/internal/cmd/root.go index 02c05db511f6a28b4b7b907c2fbc1edcabede549..c1afc25f7a5555c586c43725f40bf708a18ed36f 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -173,7 +173,7 @@ func setupAppWithProgressBar(cmd *cobra.Command) (*app.App, error) { } // Check if progress bar is enabled in config (defaults to true if nil) - progressEnabled := app.Config().Options.Progress == nil || *app.Config().Options.Progress + progressEnabled := app.ConfigService().Progress() == nil || *app.ConfigService().Progress() if progressEnabled && supportsProgressBar() { _, _ = fmt.Fprintf(os.Stderr, ansi.SetIndeterminateProgressBar) defer func() { _, _ = fmt.Fprintf(os.Stderr, ansi.ResetProgressBar) }() @@ -206,18 +206,18 @@ func setupApp(cmd *cobra.Command) (*app.App, error) { } cfg.Permissions.SkipRequests = yolo - if err := createDotCrushDir(cfg.Options.DataDirectory); err != nil { + if err := createDotCrushDir(svc.DataDirectory()); err != nil { return nil, err } // Register this project in the centralized projects list. - if err := projects.Register(cwd, cfg.Options.DataDirectory); err != nil { + if err := projects.Register(cwd, svc.DataDirectory()); err != nil { slog.Warn("Failed to register project", "error", err) // Non-fatal: continue even if registration fails } // Connect to DB; this will also run migrations. - conn, err := db.Connect(ctx, cfg.Options.DataDirectory) + conn, err := db.Connect(ctx, svc.DataDirectory()) if err != nil { return nil, err } @@ -228,21 +228,21 @@ func setupApp(cmd *cobra.Command) (*app.App, error) { return nil, err } - if shouldEnableMetrics(cfg) { + if shouldEnableMetrics(svc) { event.Init() } return appInstance, nil } -func shouldEnableMetrics(cfg *config.Config) bool { +func shouldEnableMetrics(svc *config.Service) bool { if v, _ := strconv.ParseBool(os.Getenv("CRUSH_DISABLE_METRICS")); v { return false } if v, _ := strconv.ParseBool(os.Getenv("DO_NOT_TRACK")); v { return false } - if cfg.Options.DisableMetrics { + if svc.DisableMetrics() { return false } return true diff --git a/internal/config/service.go b/internal/config/service.go index b85b54d5f8f8bcaeb065a2176ccb2622fedaafc6..9d2ad52f1665af79e09e89e841f5948f5ef10447 100644 --- a/internal/config/service.go +++ b/internal/config/service.go @@ -124,6 +124,148 @@ func (s *Service) Agents() map[string]Agent { return s.agents } +// Agent returns the agent configuration for the given name and +// whether it exists. +func (s *Service) Agent(name string) (Agent, bool) { + a, ok := s.agents[name] + return a, ok +} + +// DataDirectory returns the data directory path. +func (s *Service) DataDirectory() string { + return s.cfg.Options.DataDirectory +} + +// Debug returns whether debug mode is enabled. +func (s *Service) Debug() bool { + return s.cfg.Options.Debug +} + +// DebugLSP returns whether LSP debug mode is enabled. +func (s *Service) DebugLSP() bool { + return s.cfg.Options.DebugLSP +} + +// DisableAutoSummarize returns whether auto-summarization is +// disabled. +func (s *Service) DisableAutoSummarize() bool { + return s.cfg.Options.DisableAutoSummarize +} + +// Attribution returns the attribution settings. +func (s *Service) Attribution() *Attribution { + return s.cfg.Options.Attribution +} + +// ContextPaths returns the configured context paths. +func (s *Service) ContextPaths() []string { + return s.cfg.Options.ContextPaths +} + +// SkillsPaths returns the configured skills paths. +func (s *Service) SkillsPaths() []string { + return s.cfg.Options.SkillsPaths +} + +// Progress returns the progress setting pointer. +func (s *Service) Progress() *bool { + return s.cfg.Options.Progress +} + +// DisableMetrics returns whether metrics are disabled. +func (s *Service) DisableMetrics() bool { + return s.cfg.Options.DisableMetrics +} + +// SelectedModel returns the selected model for the given type and +// whether it exists. +func (s *Service) SelectedModel(modelType SelectedModelType) (SelectedModel, bool) { + m, ok := s.cfg.Models[modelType] + return m, ok +} + +// MCP returns the MCP configurations. +func (s *Service) MCP() MCPs { + return s.cfg.MCP +} + +// LSP returns the LSP configurations. +func (s *Service) LSP() LSPs { + return s.cfg.LSP +} + +// Permissions returns the permissions configuration. +func (s *Service) Permissions() *Permissions { + return s.cfg.Permissions +} + +// SetPermissions sets the permissions configuration. +func (s *Service) SetPermissions(p *Permissions) { + s.cfg.Permissions = p +} + +// ToolLsConfig returns the ls tool configuration. +func (s *Service) ToolLsConfig() ToolLs { + return s.cfg.Tools.Ls +} + +// CompactMode returns whether compact mode is enabled. +func (s *Service) CompactMode() bool { + if s.cfg.Options.TUI == nil { + return false + } + return s.cfg.Options.TUI.CompactMode +} + +// DiffMode returns the diff mode setting. +func (s *Service) DiffMode() string { + if s.cfg.Options.TUI == nil { + return "" + } + return s.cfg.Options.TUI.DiffMode +} + +// CompletionLimits returns the completion depth and items limits. +func (s *Service) CompletionLimits() (depth, items int) { + if s.cfg.Options.TUI == nil { + return 0, 0 + } + return s.cfg.Options.TUI.Completions.Limits() +} + +// DisableDefaultProviders returns whether default providers are +// disabled. +func (s *Service) DisableDefaultProviders() bool { + return s.cfg.Options.DisableDefaultProviders +} + +// DisableProviderAutoUpdate returns whether provider auto-update is +// disabled. +func (s *Service) DisableProviderAutoUpdate() bool { + return s.cfg.Options.DisableProviderAutoUpdate +} + +// InitializeAs returns the initialization file name. +func (s *Service) InitializeAs() string { + return s.cfg.Options.InitializeAs +} + +// AutoLSP returns the auto-LSP setting pointer. +func (s *Service) AutoLSP() *bool { + return s.cfg.Options.AutoLSP +} + +// RecentModels returns recent models for the given type. +func (s *Service) RecentModels(modelType SelectedModelType) []SelectedModel { + return s.cfg.RecentModels[modelType] +} + +// Options returns the full options struct. This is a temporary +// accessor for callers that need multiple option fields. +func (s *Service) Options() *Options { + return s.cfg.Options +} + // HasConfigField returns true if the given dotted key path exists in // the persisted config data. func (s *Service) HasConfigField(key string) bool { diff --git a/internal/ui/model/header.go b/internal/ui/model/header.go index 5af9d93a027f9da30ac4774260f1c8f2b5100940..2f3ddf050f9bb590ed49d706a4e3e3666310b4a5 100644 --- a/internal/ui/model/header.go +++ b/internal/ui/model/header.go @@ -117,7 +117,7 @@ func renderHeaderDetails( parts = append(parts, t.LSP.ErrorDiagnostic.Render(fmt.Sprintf("%s%d", styles.LSPErrorIcon, errorCount))) } - agentCfg := com.Config().Agents[config.AgentCoder] + agentCfg := com.ConfigService().Agents()[config.AgentCoder] model := com.ConfigService().GetModelByType(agentCfg.Model) percentage := (float64(session.CompletionTokens+session.PromptTokens) / float64(model.ContextWindow)) * 100 formattedPercentage := t.Header.Percentage.Render(fmt.Sprintf("%d%%", int(percentage))) diff --git a/internal/ui/model/mcp.go b/internal/ui/model/mcp.go index 40be8619133268edbc53cf2bee863ed89a2af00f..7eb8f45ffccd307b0197af3ad11106ebce549a40 100644 --- a/internal/ui/model/mcp.go +++ b/internal/ui/model/mcp.go @@ -16,7 +16,7 @@ func (m *UI) mcpInfo(width, maxItems int, isSection bool) string { var mcps []mcp.ClientInfo t := m.com.Styles - for _, mcp := range m.com.Config().MCP.Sorted() { + for _, mcp := range m.com.ConfigService().MCP().Sorted() { if state, ok := m.mcpStates[mcp.Name]; ok { mcps = append(mcps, state) } diff --git a/internal/ui/model/sidebar.go b/internal/ui/model/sidebar.go index e4107ceca26e851d9cf18be19e944b0f27db4d69..001242fad9f2b01f437e1cf3caca39a062175a77 100644 --- a/internal/ui/model/sidebar.go +++ b/internal/ui/model/sidebar.go @@ -21,7 +21,7 @@ func (m *UI) modelInfo(width int) string { if model != nil { // Get provider name first - providerConfig, ok := m.com.Config().Providers.Get(model.ModelCfg.Provider) + providerConfig, ok := m.com.ConfigService().Config().Providers.Get(model.ModelCfg.Provider) if ok { providerName = providerConfig.Name diff --git a/internal/ui/model/ui.go b/internal/ui/model/ui.go index 3ab0caee90ea78990469deda4852bdac7d1e5c05..29e7142a05099c73d81bdb0a1569cefc3ad3643e 100644 --- a/internal/ui/model/ui.go +++ b/internal/ui/model/ui.go @@ -289,7 +289,7 @@ func New(com *common.Common) *UI { ui.status = status // Initialize compact mode from config - ui.forceCompactMode = com.Config().Options.TUI.CompactMode + ui.forceCompactMode = com.ConfigService().Options().TUI.CompactMode // set onboarding state defaults ui.onboarding.yesInitializeSelected = true @@ -305,7 +305,7 @@ func New(com *common.Common) *UI { // set initial state ui.setState(desiredState, desiredFocus) - opts := com.Config().Options + opts := com.ConfigService().Options() // disable indeterminate progress bar ui.progressBarEnabled = opts.Progress == nil || *opts.Progress @@ -1635,7 +1635,7 @@ func (m *UI) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd { m.completionsQuery = "" m.completionsStartIndex = curIdx m.completionsPositionStart = m.completionsPosition() - depth, limit := m.com.Config().Options.TUI.Completions.Limits() + depth, limit := m.com.ConfigService().Options().TUI.Completions.Limits() cmds = append(cmds, m.completions.OpenWithFiles(depth, limit)) } } @@ -2848,7 +2848,7 @@ func (m *UI) openPermissionsDialog(perm permission.PermissionRequest) tea.Cmd { // Get diff mode from config. var opts []dialog.PermissionsOption - if diffMode := m.com.Config().Options.TUI.DiffMode; diffMode != "" { + if diffMode := m.com.ConfigService().Options().TUI.DiffMode; diffMode != "" { opts = append(opts, dialog.WithDiffMode(diffMode == "split")) }