From ab475a4ce82b5bbe6b05330c37a03eaa658249b7 Mon Sep 17 00:00:00 2001 From: Charm <124303983+charmcli@users.noreply.github.com> Date: Wed, 18 Feb 2026 07:38:04 -0300 Subject: [PATCH 01/50] chore(legal): @julienrbrt has signed the CLA --- .github/cla-signatures.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/cla-signatures.json b/.github/cla-signatures.json index cffebabffd242a4897a07d79e1e0d051c7662cc2..018f4fd81763b24f05111de5e8c1273d1ff89f22 100644 --- a/.github/cla-signatures.json +++ b/.github/cla-signatures.json @@ -1263,6 +1263,14 @@ "created_at": "2026-02-16T09:16:57Z", "repoId": 987670088, "pullRequestNo": 2236 + }, + { + "name": "julienrbrt", + "id": 29894366, + "comment_id": 3920039276, + "created_at": "2026-02-18T10:37:53Z", + "repoId": 987670088, + "pullRequestNo": 2246 } ] } \ No newline at end of file From 540deef219de0646cf531fd4874d09f7c01cffa1 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Wed, 18 Feb 2026 17:22:43 +0300 Subject: [PATCH 02/50] fix(ui): toggle pills to follow scroll (#2218) This change ensures that when toggling the pills (e.g., to-dos) in the UI, if the scroll follow mode is enabled, the chat will automatically scroll to the bottom. This prevents the user from losing their place in the chat when they expand or collapse the pills section. --- internal/ui/model/pills.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/internal/ui/model/pills.go b/internal/ui/model/pills.go index fb3dcc1e3a86cb63d9e0a267476863a6260d0816..9b3307135aec89105adb895ef07bbe30484ec658 100644 --- a/internal/ui/model/pills.go +++ b/internal/ui/model/pills.go @@ -139,11 +139,6 @@ func (m *UI) togglePillsExpanded() tea.Cmd { if !m.hasSession() { return nil } - if m.layout.pills.Dy() > 0 { - if cmd := m.chat.ScrollByAndAnimate(0); cmd != nil { - return cmd - } - } hasPills := hasIncompleteTodos(m.session.Todos) || m.promptQueue > 0 if !hasPills { return nil @@ -157,6 +152,12 @@ func (m *UI) togglePillsExpanded() tea.Cmd { } } m.updateLayoutAndSize() + + // Make sure to follow scroll if follow is enabled when toggling pills. + if m.chat.Follow() { + m.chat.ScrollToBottom() + } + return nil } From eecb1bfe22c36451003f65d1b30dac81e2e2ccaf Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Tue, 17 Feb 2026 13:21:58 -0300 Subject: [PATCH 03/50] perf: remove mutex from lsp manager - used the synchronized client map - lsps root markers don't need to be gitignore aware - cache unexisting lsp binaries globally closes #2223 Signed-off-by: Carlos Alexandro Becker --- internal/agent/tools/glob.go | 2 +- internal/fsext/fileutil.go | 18 +++++-- internal/fsext/fileutil_test.go | 26 +++++----- internal/lsp/client.go | 2 +- internal/lsp/manager.go | 92 +++++++++++++++++++-------------- internal/ui/model/lsp.go | 2 +- 6 files changed, 83 insertions(+), 59 deletions(-) diff --git a/internal/agent/tools/glob.go b/internal/agent/tools/glob.go index 3f56d9dcb6437d5ad6c9ca3b8416ae45c6eb7969..1117e57858e07bbcf8c401e98fd7e66be13140ff 100644 --- a/internal/agent/tools/glob.go +++ b/internal/agent/tools/glob.go @@ -81,7 +81,7 @@ func globFiles(ctx context.Context, pattern, searchPath string, limit int) ([]st slog.Warn("Ripgrep execution failed, falling back to doublestar", "error", err) } - return fsext.GlobWithDoubleStar(pattern, searchPath, limit) + return fsext.GlobGitignoreAware(pattern, searchPath, limit) } func runRipgrep(cmd *exec.Cmd, searchRoot string, limit int) ([]string, error) { diff --git a/internal/fsext/fileutil.go b/internal/fsext/fileutil.go index c091820935d9c13142b12d3bd79d8c023a42a2fd..72410a10721ae6af1965942d455a8310096399e6 100644 --- a/internal/fsext/fileutil.go +++ b/internal/fsext/fileutil.go @@ -82,7 +82,19 @@ func (w *FastGlobWalker) ShouldSkipDir(path string) bool { return w.directoryLister.shouldIgnore(path, nil, true) } -func GlobWithDoubleStar(pattern, searchPath string, limit int) ([]string, bool, error) { +// Glob globs files. +// +// Does not respect gitignore. +func Glob(pattern string, cwd string, limit int) ([]string, bool, error) { + return globWithDoubleStar(pattern, cwd, limit, false) +} + +// GlobGitignoreAware globs files respecting gitignore. +func GlobGitignoreAware(pattern string, cwd string, limit int) ([]string, bool, error) { + return globWithDoubleStar(pattern, cwd, limit, true) +} + +func globWithDoubleStar(pattern, searchPath string, limit int, gitignore bool) ([]string, bool, error) { // Normalize pattern to forward slashes on Windows so their config can use // backslashes pattern = filepath.ToSlash(pattern) @@ -101,11 +113,11 @@ func GlobWithDoubleStar(pattern, searchPath string, limit int) ([]string, bool, isDir := d.IsDir() if isDir { - if walker.ShouldSkipDir(path) { + if gitignore && walker.ShouldSkipDir(path) { return filepath.SkipDir } } else { - if walker.ShouldSkip(path) { + if gitignore && walker.ShouldSkip(path) { return nil } } diff --git a/internal/fsext/fileutil_test.go b/internal/fsext/fileutil_test.go index 3788fe5477b082dec496275a8ac028788d55fc64..e80b902c08301be3a6b02e9a8d0e9c82895410b3 100644 --- a/internal/fsext/fileutil_test.go +++ b/internal/fsext/fileutil_test.go @@ -24,7 +24,7 @@ func TestGlobWithDoubleStar(t *testing.T) { require.NoError(t, os.WriteFile(file, []byte("test content"), 0o644)) } - matches, truncated, err := GlobWithDoubleStar("**/main.go", testDir, 0) + matches, truncated, err := GlobGitignoreAware("**/main.go", testDir, 0) require.NoError(t, err) require.False(t, truncated) @@ -47,7 +47,7 @@ func TestGlobWithDoubleStar(t *testing.T) { require.NoError(t, os.WriteFile(filepath.Join(srcDir, "main.go"), []byte("package main"), 0o644)) require.NoError(t, os.WriteFile(pkgFile, []byte("test"), 0o644)) - matches, truncated, err := GlobWithDoubleStar("pkg", testDir, 0) + matches, truncated, err := GlobGitignoreAware("pkg", testDir, 0) require.NoError(t, err) require.False(t, truncated) @@ -66,7 +66,7 @@ func TestGlobWithDoubleStar(t *testing.T) { require.NoError(t, os.MkdirAll(dir, 0o755)) } - matches, truncated, err := GlobWithDoubleStar("**/pkg", testDir, 0) + matches, truncated, err := GlobGitignoreAware("**/pkg", testDir, 0) require.NoError(t, err) require.False(t, truncated) @@ -95,7 +95,7 @@ func TestGlobWithDoubleStar(t *testing.T) { require.NoError(t, os.WriteFile(file, []byte("package main"), 0o644)) } - matches, truncated, err := GlobWithDoubleStar("pkg/**", testDir, 0) + matches, truncated, err := GlobGitignoreAware("pkg/**", testDir, 0) require.NoError(t, err) require.False(t, truncated) @@ -124,7 +124,7 @@ func TestGlobWithDoubleStar(t *testing.T) { require.NoError(t, os.WriteFile(file, []byte("test"), 0o644)) } - matches, truncated, err := GlobWithDoubleStar("**/*.txt", testDir, 5) + matches, truncated, err := GlobGitignoreAware("**/*.txt", testDir, 5) require.NoError(t, err) require.True(t, truncated, "Expected truncation with limit") require.Len(t, matches, 5, "Expected exactly 5 matches with limit") @@ -143,7 +143,7 @@ func TestGlobWithDoubleStar(t *testing.T) { require.NoError(t, os.WriteFile(file, []byte("test"), 0o644)) } - matches, truncated, err := GlobWithDoubleStar("a/b/c/file1.txt", testDir, 0) + matches, truncated, err := GlobGitignoreAware("a/b/c/file1.txt", testDir, 0) require.NoError(t, err) require.False(t, truncated) @@ -171,7 +171,7 @@ func TestGlobWithDoubleStar(t *testing.T) { require.NoError(t, os.Chtimes(file2, m2, m2)) require.NoError(t, os.Chtimes(file3, m3, m3)) - matches, truncated, err := GlobWithDoubleStar("*.txt", testDir, 0) + matches, truncated, err := GlobGitignoreAware("*.txt", testDir, 0) require.NoError(t, err) require.False(t, truncated) @@ -181,7 +181,7 @@ func TestGlobWithDoubleStar(t *testing.T) { t.Run("handles empty directory", func(t *testing.T) { testDir := t.TempDir() - matches, truncated, err := GlobWithDoubleStar("**", testDir, 0) + matches, truncated, err := GlobGitignoreAware("**", testDir, 0) require.NoError(t, err) require.False(t, truncated) // Even empty directories should return the directory itself @@ -191,7 +191,7 @@ func TestGlobWithDoubleStar(t *testing.T) { t.Run("handles non-existent search path", func(t *testing.T) { nonExistentDir := filepath.Join(t.TempDir(), "does", "not", "exist") - matches, truncated, err := GlobWithDoubleStar("**", nonExistentDir, 0) + matches, truncated, err := GlobGitignoreAware("**", nonExistentDir, 0) require.Error(t, err, "Should return error for non-existent search path") require.False(t, truncated) require.Empty(t, matches) @@ -219,17 +219,17 @@ func TestGlobWithDoubleStar(t *testing.T) { ignoredFileInDir := filepath.Join(testDir, "backup", "old.txt") require.NoError(t, os.WriteFile(ignoredFileInDir, []byte("old content"), 0o644)) - matches, truncated, err := GlobWithDoubleStar("*.tmp", testDir, 0) + matches, truncated, err := GlobGitignoreAware("*.tmp", testDir, 0) require.NoError(t, err) require.False(t, truncated) require.Empty(t, matches, "Expected no matches for '*.tmp' pattern (should be ignored)") - matches, truncated, err = GlobWithDoubleStar("backup", testDir, 0) + matches, truncated, err = GlobGitignoreAware("backup", testDir, 0) require.NoError(t, err) require.False(t, truncated) require.Empty(t, matches, "Expected no matches for 'backup' pattern (should be ignored)") - matches, truncated, err = GlobWithDoubleStar("*.txt", testDir, 0) + matches, truncated, err = GlobGitignoreAware("*.txt", testDir, 0) require.NoError(t, err) require.False(t, truncated) require.Equal(t, []string{goodFile}, matches) @@ -257,7 +257,7 @@ func TestGlobWithDoubleStar(t *testing.T) { require.NoError(t, os.Chtimes(middleDir, tMiddle, tMiddle)) require.NoError(t, os.Chtimes(oldestFile, tNewest, tNewest)) - matches, truncated, err := GlobWithDoubleStar("*.rs", testDir, 0) + matches, truncated, err := GlobGitignoreAware("*.rs", testDir, 0) require.NoError(t, err) require.False(t, truncated) require.Len(t, matches, 3) diff --git a/internal/lsp/client.go b/internal/lsp/client.go index c82dffabf40e99dc932e2fd326b24031d3e04ebb..3d7f07f977b1ef61bd20652d6bdc6a9b3643383a 100644 --- a/internal/lsp/client.go +++ b/internal/lsp/client.go @@ -85,7 +85,7 @@ func New( resolver: resolver, cwd: cwd, } - client.serverState.Store(StateStarting) + client.serverState.Store(StateStopped) if err := client.createPowernapClient(); err != nil { return nil, err diff --git a/internal/lsp/manager.go b/internal/lsp/manager.go index efa7596a685786e3a3c4053eb94f8858c7549e9f..381700d1299454bd241aeeaf6525686e6c44d45c 100644 --- a/internal/lsp/manager.go +++ b/internal/lsp/manager.go @@ -21,13 +21,14 @@ import ( "github.com/sourcegraph/jsonrpc2" ) +var unavailable = csync.NewMap[string, struct{}]() + // Manager handles lazy initialization of LSP clients based on file types. type Manager struct { clients *csync.Map[string, *Client] cfg *config.Config manager *powernapconfig.Manager callback func(name string, client *Client) - mu sync.Mutex } // NewManager creates a new LSP manager service. @@ -72,17 +73,12 @@ func (s *Manager) Clients() *csync.Map[string, *Client] { // SetCallback sets a callback that is invoked when a new LSP // client is successfully started. This allows the coordinator to add LSP tools. func (s *Manager) SetCallback(cb func(name string, client *Client)) { - s.mu.Lock() - defer s.mu.Unlock() s.callback = cb } // TrackConfigured will callback the user-configured LSPs, but will not create // any clients. func (s *Manager) TrackConfigured() { - s.mu.Lock() - defer s.mu.Unlock() - var wg sync.WaitGroup for name := range s.manager.GetServers() { if !s.isUserConfigured(name) { @@ -102,16 +98,10 @@ func (s *Manager) Start(ctx context.Context, path string) { return } - s.mu.Lock() - defer s.mu.Unlock() - var wg sync.WaitGroup for name, server := range s.manager.GetServers() { - if !handles(server, path, s.cfg.WorkingDir()) { - continue - } wg.Go(func() { - s.startServer(ctx, name, server) + s.startServer(ctx, name, path, server) }) } wg.Wait() @@ -149,12 +139,31 @@ var skipAutoStartCommands = map[string]bool{ "tflint": true, } -func (s *Manager) startServer(ctx context.Context, name string, server *powernapconfig.ServerConfig) { +func (s *Manager) startServer(ctx context.Context, name, filepath string, server *powernapconfig.ServerConfig) { + cfg := s.buildConfig(name, server) + if cfg.Disabled { + return + } + + if _, exists := unavailable.Get(name); exists { + return + } + + if client, ok := s.clients.Get(name); ok { + switch client.GetServerState() { + case StateReady, StateStarting, StateDisabled: + s.callback(name, client) + // already done, return + return + } + } + userConfigured := s.isUserConfigured(name) if !userConfigured { if _, err := exec.LookPath(server.Command); err != nil { slog.Debug("LSP server not installed, skipping", "name", name, "command", server.Command) + unavailable.Set(name, struct{}{}) return } if skipAutoStartCommands[server.Command] { @@ -163,34 +172,43 @@ func (s *Manager) startServer(ctx context.Context, name string, server *powernap } } - cfg := s.buildConfig(name, server) - if client, ok := s.clients.Get(name); ok { - switch client.GetServerState() { - case StateReady, StateStarting: - s.callback(name, client) - // already done, return - return - } + // this is the slowest bit, so we do it last. + if !handles(server, filepath, s.cfg.WorkingDir()) { + // nothing to do + return } - client, err := New( - ctx, - name, - cfg, - s.cfg.Resolver(), - s.cfg.WorkingDir(), - s.cfg.Options.DebugLSP, - ) + + // check again in case another goroutine started it in the meantime + var err error + client := s.clients.GetOrSet(name, func() *Client { + var cli *Client + cli, err = New( + ctx, + name, + cfg, + s.cfg.Resolver(), + s.cfg.WorkingDir(), + s.cfg.Options.DebugLSP, + ) + return cli + }) if err != nil { slog.Error("Failed to create LSP client", "name", name, "error", err) return } - s.callback(name, client) - defer func() { - s.clients.Set(name, client) s.callback(name, client) }() + switch client.GetServerState() { + case StateReady, StateStarting: + // already done, return + return + } + + client.serverState.Store(StateStarting) + s.callback(name, client) + initCtx, cancel := context.WithTimeout(ctx, time.Duration(cmp.Or(cfg.Timeout, 30))*time.Second) defer cancel() @@ -271,7 +289,7 @@ func hasRootMarkers(dir string, markers []string) bool { } for _, pattern := range markers { // Use fsext.GlobWithDoubleStar to find matches - matches, _, err := fsext.GlobWithDoubleStar(pattern, dir, 1) + matches, _, err := fsext.Glob(pattern, dir, 1) if err == nil && len(matches) > 0 { return true } @@ -291,9 +309,6 @@ func handles(server *powernapconfig.ServerConfig, filePath, workDir string) bool // in the middle of writing something. // Generally it doesn't matter when shutting down Crush, though. func (s *Manager) KillAll(context.Context) { - s.mu.Lock() - defer s.mu.Unlock() - var wg sync.WaitGroup for name, client := range s.clients.Seq2() { wg.Go(func() { @@ -308,9 +323,6 @@ func (s *Manager) KillAll(context.Context) { // StopAll stops all running LSP clients and clears the client map. func (s *Manager) StopAll(ctx context.Context) { - s.mu.Lock() - defer s.mu.Unlock() - var wg sync.WaitGroup for name, client := range s.clients.Seq2() { wg.Go(func() { diff --git a/internal/ui/model/lsp.go b/internal/ui/model/lsp.go index 87de0d39d20520b3b24f5da3861efe7d5f9fe4a5..1458d3402cbfa1536e5bef31f7d72ac5d58dddfe 100644 --- a/internal/ui/model/lsp.go +++ b/internal/ui/model/lsp.go @@ -108,7 +108,7 @@ func lspList(t *styles.Styles, lsps []LSPInfo, width, maxItems int) string { icon = t.ResourceOfflineIcon.Foreground(t.Muted.GetBackground()).String() description = t.ResourceStatus.Render("disabled") default: - icon = t.ResourceOfflineIcon.String() + continue } renderedLsps = append(renderedLsps, common.Status(t, common.StatusOpts{ Icon: icon, From 7ac4061b6c8af87e05edbf6bfaa94ded48315545 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Wed, 18 Feb 2026 14:19:49 -0300 Subject: [PATCH 04/50] fix(lsp): properly remove clients from map on stop/kill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Delete clients from the map in StopAll and KillAll so they can be recreated on restart - Add StateDisabled to the state check to prevent re-initializing disabled clients - Remove duplicate callback invocation in startServer 💘 Generated with Crush Assisted-by: Kimi K2.5 via Crush --- internal/lsp/manager.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/lsp/manager.go b/internal/lsp/manager.go index 381700d1299454bd241aeeaf6525686e6c44d45c..44f04e9a6e005a9217b4f62e3f3b477f1ff85838 100644 --- a/internal/lsp/manager.go +++ b/internal/lsp/manager.go @@ -201,13 +201,12 @@ func (s *Manager) startServer(ctx context.Context, name, filepath string, server }() switch client.GetServerState() { - case StateReady, StateStarting: + case StateReady, StateStarting, StateDisabled: // already done, return return } client.serverState.Store(StateStarting) - s.callback(name, client) initCtx, cancel := context.WithTimeout(ctx, time.Duration(cmp.Or(cfg.Timeout, 30))*time.Second) defer cancel() @@ -315,6 +314,7 @@ func (s *Manager) KillAll(context.Context) { defer func() { s.callback(name, client) }() client.client.Kill() client.SetServerState(StateStopped) + s.clients.Del(name) slog.Debug("Killed LSP client", "name", name) }) } @@ -335,6 +335,7 @@ func (s *Manager) StopAll(ctx context.Context) { slog.Warn("Failed to stop LSP client", "name", name, "error", err) } client.SetServerState(StateStopped) + s.clients.Del(name) slog.Debug("Stopped LSP client", "name", name) }) } From 7fe592d73c354ef85fe2a071998c40217b888760 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Wed, 18 Feb 2026 14:53:44 -0300 Subject: [PATCH 05/50] fix: make reasoning effort dialog smaller (#2247) Before, it was even wider than the commands dialog, which looked weird. --- internal/ui/dialog/reasoning.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/ui/dialog/reasoning.go b/internal/ui/dialog/reasoning.go index 2a333f155cdc1499993f05411d7090793f74f54e..cd8ba7d1e293fcb66d04c76f420463aa3a94770f 100644 --- a/internal/ui/dialog/reasoning.go +++ b/internal/ui/dialog/reasoning.go @@ -20,8 +20,8 @@ import ( const ( // ReasoningID is the identifier for the reasoning effort dialog. ReasoningID = "reasoning" - reasoningDialogMaxWidth = 80 - reasoningDialogMaxHeight = 12 + reasoningDialogMaxWidth = 50 + reasoningDialogMaxHeight = 10 ) // Reasoning represents a dialog for selecting reasoning effort. From db5e9cc607724cd0553a88b4ccbe866c0fb39ae7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 15:03:59 -0300 Subject: [PATCH 06/50] chore(deps): bump github/codeql-action in the all group (#2237) Bumps the all group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 4.32.2 to 4.32.3 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2...9e907b5e64f6b83e7804b09294d44122997950d6) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.32.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/security.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 9f1bed1c8ccead5603f6b868e018b4872dbfc1bb..29a71ffe1b435ed6a297e16a4912cec89b2e8df3 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -30,11 +30,11 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - uses: github/codeql-action/init@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2 + - uses: github/codeql-action/init@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 with: languages: ${{ matrix.language }} - - uses: github/codeql-action/autobuild@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2 - - uses: github/codeql-action/analyze@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2 + - uses: github/codeql-action/autobuild@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 + - uses: github/codeql-action/analyze@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 grype: runs-on: ubuntu-latest @@ -52,7 +52,7 @@ jobs: path: "." fail-build: true severity-cutoff: critical - - uses: github/codeql-action/upload-sarif@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2 + - uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 with: sarif_file: ${{ steps.scan.outputs.sarif }} @@ -73,7 +73,7 @@ jobs: - name: Run govulncheck run: | govulncheck -C . -format sarif ./... > results.sarif - - uses: github/codeql-action/upload-sarif@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2 + - uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 with: sarif_file: results.sarif From df0dfbed15c573f69603262282901db8743c9142 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Wed, 18 Feb 2026 15:02:05 -0300 Subject: [PATCH 07/50] ci(labeler): add minimax label --- .github/labeler.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/labeler.yml b/.github/labeler.yml index e0e998246f6533415b9c356ccae8d905e0afe1df..a0270f4f4ad0873aa7eb04b5b34bcb703ef859b9 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -57,6 +57,8 @@ - "/vertex/i" "provider: kimi": - "/kimi/i" +"provider: minimax": + - "/minimax/i" "provider: ollama": - "/llama/i" "provider: openai chatgpt": From 8f613dbcb306a38003f995140d3ec60760c5faf9 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Wed, 18 Feb 2026 15:02:21 -0300 Subject: [PATCH 08/50] ci: skip intermittent test on windows --- internal/agent/tools/job_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/agent/tools/job_test.go b/internal/agent/tools/job_test.go index f3958bef19aa6b29240eb8b265e36b56398d364e..7c8cb8f32dcdce7fe4227f05b14cc9b04e879bee 100644 --- a/internal/agent/tools/job_test.go +++ b/internal/agent/tools/job_test.go @@ -2,6 +2,7 @@ package tools import ( "context" + "runtime" "testing" "time" @@ -98,6 +99,10 @@ func TestBackgroundShell_MultipleOutputCalls(t *testing.T) { func TestBackgroundShell_EmptyOutput(t *testing.T) { t.Parallel() + if runtime.GOOS == "windows" { + t.Skip("This test is flacky on Windows for some reason") + } + workingDir := t.TempDir() ctx := context.Background() From 44c7535a5ebf75fa57107c7b25348e1fda69b9d9 Mon Sep 17 00:00:00 2001 From: Wallace Gibbon Date: Thu, 19 Feb 2026 02:35:11 +0800 Subject: [PATCH 09/50] fix(deps): update `go-nativeclipboard` version to compile to RISC-V. (#2216) --- go.mod | 9 ++++----- go.sum | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 7672d9c5ab326a39ce1374622c1746f80099672f..c61066077cd1b60fe93c6875b42e9301a1785d85 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/PuerkitoBio/goquery v1.11.0 github.com/alecthomas/chroma/v2 v2.23.1 github.com/atotto/clipboard v0.1.4 - github.com/aymanbagabas/go-nativeclipboard v0.1.2 + github.com/aymanbagabas/go-nativeclipboard v0.1.3 github.com/aymanbagabas/go-udiff v0.3.1 github.com/bmatcuk/doublestar/v4 v4.10.0 github.com/charlievieth/fastwalk v1.0.14 @@ -64,7 +64,7 @@ require ( go.uber.org/goleak v1.3.0 golang.org/x/net v0.49.0 golang.org/x/sync v0.19.0 - golang.org/x/text v0.33.0 + golang.org/x/text v0.34.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 modernc.org/sqlite v1.44.3 @@ -106,7 +106,7 @@ require ( github.com/clipperhouse/stringish v0.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect - github.com/ebitengine/purego v0.10.0-alpha.3.0.20260102153238-200df6041cff // indirect + github.com/ebitengine/purego v0.10.0-alpha.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect @@ -173,8 +173,7 @@ require ( go.yaml.in/yaml/v4 v4.0.0-rc.3 // indirect golang.org/x/crypto v0.47.0 // indirect golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect - golang.org/x/image v0.34.0 // indirect - golang.org/x/mod v0.32.0 // indirect + golang.org/x/image v0.36.0 // indirect golang.org/x/oauth2 v0.35.0 // indirect golang.org/x/sys v0.41.0 // indirect golang.org/x/term v0.39.0 // indirect diff --git a/go.sum b/go.sum index 81b47ce5913a63c5926298fa5ca94bbc0572a729..2f1d09ae6a8b4a2afa1dc391abce8cf4651519e0 100644 --- a/go.sum +++ b/go.sum @@ -78,8 +78,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/ github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ= github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= -github.com/aymanbagabas/go-nativeclipboard v0.1.2 h1:Z2iVRWQ4IynMLWM6a+lWH2Nk5gPyEtPRMuBIyZ2dECM= -github.com/aymanbagabas/go-nativeclipboard v0.1.2/go.mod h1:BVJhN7hs5DieCzUB2Atf4Yk9Y9kFe62E95+gOjpJq6Q= +github.com/aymanbagabas/go-nativeclipboard v0.1.3 h1:FmAWHPTwneAixu7uGDn3cL42xPlUCdNp2J8egMn3P1k= +github.com/aymanbagabas/go-nativeclipboard v0.1.3/go.mod h1:2o7MyZwwi4pmXXpOpvOS5FwaHyoCIUks0ktjUvB0EoE= github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY= github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= @@ -150,8 +150,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/ebitengine/purego v0.10.0-alpha.3.0.20260102153238-200df6041cff h1:vAcU1VsCRstZ9ty11yD/L0WDyT73S/gVfmuWvcWX5DA= -github.com/ebitengine/purego v0.10.0-alpha.3.0.20260102153238-200df6041cff/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.10.0-alpha.4 h1:JzPbdf+cqbyT9sZtP4xnqelwUXwf7LvD8xKS6+ofTds= +github.com/ebitengine/purego v0.10.0-alpha.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= @@ -399,8 +399,8 @@ golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4 golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.34.0 h1:33gCkyw9hmwbZJeZkct8XyR11yH889EQt/QH4VmXMn8= -golang.org/x/image v0.34.0/go.mod h1:2RNFBZRB+vnwwFil8GkMdRvrJOFd1AzdZI6vOY+eJVU= +golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc= +golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= @@ -472,8 +472,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -482,8 +482,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= -golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= From 699c8d79c3ac44fa676c00c674e5ed8787a0bfeb Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Wed, 18 Feb 2026 16:32:46 -0300 Subject: [PATCH 10/50] refactor: simplify some code by using `cmp.Or` (#2253) --- internal/agent/agent.go | 5 +---- internal/agent/tools/glob.go | 6 ++---- internal/agent/tools/grep.go | 6 ++---- internal/agent/tools/list_mcp_resources.go | 9 ++------- internal/config/load.go | 16 ++++------------ internal/ui/dialog/arguments.go | 6 ++---- internal/ui/dialog/models.go | 9 ++------- internal/ui/model/ui.go | 11 +++-------- 8 files changed, 18 insertions(+), 50 deletions(-) diff --git a/internal/agent/agent.go b/internal/agent/agent.go index 2671577b85efef5ebf8b75fa6167bc0ec46eff3b..a046c6b2d44d6f7d07300fae7ec5ac38f8ae03b8 100644 --- a/internal/agent/agent.go +++ b/internal/agent/agent.go @@ -849,10 +849,7 @@ func (a *sessionAgent) generateTitle(ctx context.Context, sessionID string, user title = thinkTagRegex.ReplaceAllString(title, "") title = strings.TrimSpace(title) - if title == "" { - slog.Debug("Empty title; using fallback") - title = defaultSessionName - } + title = cmp.Or(title, defaultSessionName) // Calculate usage and cost. var openrouterCost *float64 diff --git a/internal/agent/tools/glob.go b/internal/agent/tools/glob.go index 1117e57858e07bbcf8c401e98fd7e66be13140ff..641a84dd29ff6993b1fb54d0e5675dc3f5d56ae6 100644 --- a/internal/agent/tools/glob.go +++ b/internal/agent/tools/glob.go @@ -2,6 +2,7 @@ package tools import ( "bytes" + "cmp" "context" _ "embed" "fmt" @@ -39,10 +40,7 @@ func NewGlobTool(workingDir string) fantasy.AgentTool { return fantasy.NewTextErrorResponse("pattern is required"), nil } - searchPath := params.Path - if searchPath == "" { - searchPath = workingDir - } + searchPath := cmp.Or(params.Path, workingDir) files, truncated, err := globFiles(ctx, params.Pattern, searchPath, 100) if err != nil { diff --git a/internal/agent/tools/grep.go b/internal/agent/tools/grep.go index 8c7ec51e4e3768e4814b2d6baa3c7085357f5b45..8a894a4984ac7f90f89b8a2c7f1d1c637e79aecb 100644 --- a/internal/agent/tools/grep.go +++ b/internal/agent/tools/grep.go @@ -3,6 +3,7 @@ package tools import ( "bufio" "bytes" + "cmp" "context" _ "embed" "encoding/json" @@ -115,10 +116,7 @@ func NewGrepTool(workingDir string, config config.ToolGrep) fantasy.AgentTool { searchPattern = escapeRegexPattern(params.Pattern) } - searchPath := params.Path - if searchPath == "" { - searchPath = workingDir - } + searchPath := cmp.Or(params.Path, workingDir) searchCtx, cancel := context.WithTimeout(ctx, config.GetTimeout()) defer cancel() diff --git a/internal/agent/tools/list_mcp_resources.go b/internal/agent/tools/list_mcp_resources.go index 25671ffe481a21a82c40167c40614603e907052c..032d1eb1888a65e9a14daecc3b503698a6fa60d4 100644 --- a/internal/agent/tools/list_mcp_resources.go +++ b/internal/agent/tools/list_mcp_resources.go @@ -1,6 +1,7 @@ package tools import ( + "cmp" "context" _ "embed" "fmt" @@ -74,13 +75,7 @@ func NewListMCPResourcesTool(cfg *config.Config, permissions permission.Service) if resource == nil { continue } - title := resource.Title - if title == "" { - title = resource.Name - } - if title == "" { - title = resource.URI - } + title := cmp.Or(resource.Title, resource.Name, resource.URI) line := fmt.Sprintf("- %s", title) if resource.URI != "" { line = fmt.Sprintf("%s (%s)", line, resource.URI) diff --git a/internal/config/load.go b/internal/config/load.go index 7753a50e25a4f6ed419feb1355a99c040a43d9e0..077598509796fa13b47dd0e0f05a3dbaeb4975db 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -278,13 +278,9 @@ func (c *Config) configureProviders(env env.Env, resolver VariableResolver, know // Make sure the provider ID is set providerConfig.ID = id - if providerConfig.Name == "" { - providerConfig.Name = id // Use ID as name if not set - } + providerConfig.Name = cmp.Or(providerConfig.Name, id) // Use ID as name if not set // default to OpenAI if not set - if providerConfig.Type == "" { - providerConfig.Type = catwalk.TypeOpenAICompat - } + providerConfig.Type = cmp.Or(providerConfig.Type, catwalk.TypeOpenAICompat) if !slices.Contains(catwalk.KnownProviderTypes(), providerConfig.Type) && providerConfig.Type != hyper.Name { slog.Warn("Skipping custom provider due to unsupported provider type", "provider", id) c.Providers.Del(id) @@ -412,9 +408,7 @@ func (c *Config) setDefaults(workingDir, dataDir string) { c.Options.Attribution.TrailerStyle = TrailerStyleAssistedBy } } - if c.Options.InitializeAs == "" { - c.Options.InitializeAs = defaultInitializeAs - } + c.Options.InitializeAs = cmp.Or(c.Options.InitializeAs, defaultInitializeAs) } // applyLSPDefaults applies default values from powernap to LSP configurations @@ -445,9 +439,7 @@ func (c *Config) applyLSPDefaults() { if len(cfg.RootMarkers) == 0 { cfg.RootMarkers = base.RootMarkers } - if cfg.Command == "" { - cfg.Command = base.Command - } + cfg.Command = cmp.Or(cfg.Command, base.Command) if len(cfg.Args) == 0 { cfg.Args = base.Args } diff --git a/internal/ui/dialog/arguments.go b/internal/ui/dialog/arguments.go index 5cec78593a15356b8fd18d952f78e88c7f158bab..03904651a1a75de5ac7fb7c053566ef310fcfa25 100644 --- a/internal/ui/dialog/arguments.go +++ b/internal/ui/dialog/arguments.go @@ -1,6 +1,7 @@ package dialog import ( + "cmp" "strings" "charm.land/bubbles/v2/help" @@ -311,10 +312,7 @@ func (a *Arguments) Draw(scr uv.Screen, area uv.Rectangle) *tea.Cursor { // Use standard header titleStyle := s.Dialog.Title - titleText := a.title - if titleText == "" { - titleText = "Arguments" - } + titleText := cmp.Or(a.title, "Arguments") header := common.DialogTitle(s, titleText, width, s.Primary, s.Secondary) diff --git a/internal/ui/dialog/models.go b/internal/ui/dialog/models.go index 937eac19cab996104a22751270839ebf0656a04d..977f04a61e98f79adb9bb35777fac905508f47d5 100644 --- a/internal/ui/dialog/models.go +++ b/internal/ui/dialog/models.go @@ -445,18 +445,13 @@ func (m *Models) setProviderItems() error { } continue } - if model.Name == "" { - model.Name = model.ID - } + model.Name = cmp.Or(model.Name, model.ID) displayProvider.Models = append(displayProvider.Models, model) modelIndex[model.ID] = len(displayProvider.Models) - 1 } } - name := displayProvider.Name - if name == "" { - name = providerID - } + name := cmp.Or(displayProvider.Name, providerID) group := NewModelGroup(t, name, providerConfigured) for _, model := range displayProvider.Models { diff --git a/internal/ui/model/ui.go b/internal/ui/model/ui.go index 52b12fd4ff827d5fd9ad7a8061eda81c8d767912..194fa704991b40170d945106bf502a58b98d5f72 100644 --- a/internal/ui/model/ui.go +++ b/internal/ui/model/ui.go @@ -2,6 +2,7 @@ package model import ( "bytes" + "cmp" "context" "errors" "fmt" @@ -1393,10 +1394,7 @@ func (m *UI) handleDialogMsg(msg tea.Msg) tea.Cmd { case dialog.ActionRunMCPPrompt: if len(msg.Arguments) > 0 && msg.Args == nil { m.dialog.CloseFrontDialog() - title := msg.Title - if title == "" { - title = "MCP Prompt Arguments" - } + title := cmp.Or(msg.Title, "MCP Prompt Arguments") argsDialog := dialog.NewArguments( m.com, title, @@ -2563,10 +2561,7 @@ func (m *UI) insertFileCompletion(path string) tea.Cmd { // insertMCPResourceCompletion inserts the selected resource into the textarea, // replacing the @query, and adds the resource as an attachment. func (m *UI) insertMCPResourceCompletion(item completions.ResourceCompletionValue) tea.Cmd { - displayText := item.Title - if displayText == "" { - displayText = item.URI - } + displayText := cmp.Or(item.Title, item.URI) if !m.insertCompletionText(displayText) { return nil From 2656a188bca1a241911b9145a75290d735b82b48 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Wed, 18 Feb 2026 23:22:27 +0300 Subject: [PATCH 11/50] fix(ui): cache blurred and focused renderings separately for assistant messages (#2252) Assistant messages can have long content, and rendering them can be expensive. To improve performance, we cache the rendered content for both blurred and focused states separately. --- internal/ui/chat/assistant.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/internal/ui/chat/assistant.go b/internal/ui/chat/assistant.go index 4ce71dda2515e5489900c33eb716e1d6d884409a..603beb28e9c35ffe499dc48bd2c31e2ed2c8b128 100644 --- a/internal/ui/chat/assistant.go +++ b/internal/ui/chat/assistant.go @@ -27,6 +27,8 @@ type AssistantMessageItem struct { *highlightableMessageItem *cachedMessageItem *focusableMessageItem + blurredCache *cachedMessageItem + focusedCache *cachedMessageItem message *message.Message sty *styles.Styles @@ -40,6 +42,8 @@ func NewAssistantMessageItem(sty *styles.Styles, message *message.Message) Messa a := &AssistantMessageItem{ highlightableMessageItem: defaultHighlighter(sty), cachedMessageItem: &cachedMessageItem{}, + blurredCache: &cachedMessageItem{}, + focusedCache: &cachedMessageItem{}, focusableMessageItem: &focusableMessageItem{}, message: message, sty: sty, @@ -107,11 +111,22 @@ func (a *AssistantMessageItem) RawRender(width int) string { // Render implements MessageItem. func (a *AssistantMessageItem) Render(width int) string { - style := a.sty.Chat.Message.AssistantBlurred + cache := a.blurredCache if a.focused { - style = a.sty.Chat.Message.AssistantFocused + cache = a.focusedCache } - return style.Render(a.RawRender(width)) + + content, _, ok := cache.getCachedRender(width) + if !ok { + style := a.sty.Chat.Message.AssistantBlurred + if a.focused { + style = a.sty.Chat.Message.AssistantFocused + } + content = style.Render(a.RawRender(width)) + cache.setCachedRender(content, width, lipgloss.Height(content)) + } + + return content } // renderMessageContent renders the message content including thinking, main content, and finish reason. From 72bb0866a4481e5dcb695e3d7149dcefe5185148 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 19 Feb 2026 16:25:05 +0300 Subject: [PATCH 13/50] Revert "fix(ui): cache blurred and focused renderings separately for assistant messages (#2252)" This reverts commit 2656a188bca1a241911b9145a75290d735b82b48. --- internal/ui/chat/assistant.go | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/internal/ui/chat/assistant.go b/internal/ui/chat/assistant.go index 603beb28e9c35ffe499dc48bd2c31e2ed2c8b128..4ce71dda2515e5489900c33eb716e1d6d884409a 100644 --- a/internal/ui/chat/assistant.go +++ b/internal/ui/chat/assistant.go @@ -27,8 +27,6 @@ type AssistantMessageItem struct { *highlightableMessageItem *cachedMessageItem *focusableMessageItem - blurredCache *cachedMessageItem - focusedCache *cachedMessageItem message *message.Message sty *styles.Styles @@ -42,8 +40,6 @@ func NewAssistantMessageItem(sty *styles.Styles, message *message.Message) Messa a := &AssistantMessageItem{ highlightableMessageItem: defaultHighlighter(sty), cachedMessageItem: &cachedMessageItem{}, - blurredCache: &cachedMessageItem{}, - focusedCache: &cachedMessageItem{}, focusableMessageItem: &focusableMessageItem{}, message: message, sty: sty, @@ -111,22 +107,11 @@ func (a *AssistantMessageItem) RawRender(width int) string { // Render implements MessageItem. func (a *AssistantMessageItem) Render(width int) string { - cache := a.blurredCache + style := a.sty.Chat.Message.AssistantBlurred if a.focused { - cache = a.focusedCache + style = a.sty.Chat.Message.AssistantFocused } - - content, _, ok := cache.getCachedRender(width) - if !ok { - style := a.sty.Chat.Message.AssistantBlurred - if a.focused { - style = a.sty.Chat.Message.AssistantFocused - } - content = style.Render(a.RawRender(width)) - cache.setCachedRender(content, width, lipgloss.Height(content)) - } - - return content + return style.Render(a.RawRender(width)) } // renderMessageContent renders the message content including thinking, main content, and finish reason. From ded372cbdb0761155128a43c2b469c12e4966c39 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Thu, 19 Feb 2026 10:31:41 -0300 Subject: [PATCH 14/50] ci(cla): allow prs from github copilot --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index a7b6485e6b5f89cf5a566cf9f5058dd8e72b0d23..8950de2f0a24e831d1dfc340f7cb8adf017394ea 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -29,7 +29,7 @@ jobs: path-to-signatures: ".github/cla-signatures.json" path-to-document: "https://github.com/charmbracelet/crush/blob/main/CLA.md" branch: "main" - allowlist: charmcli,charmcrush,dependabot[bot] + allowlist: charmcli,charmcrush,dependabot[bot],copilot-swe-agent[bot] custom-pr-sign-comment: "I have read the Contributor License Agreement (CLA) and hereby sign the CLA." custom-notsigned-prcomment: "Thank you for your submission. We really appreciate it! Like many open-source projects, we ask that you sign our [Contributor License Agreement](https://github.com/charmbracelet/crush/blob/main/CLA.md) before we can accept your contribution. You can sign the CLA by just posting a Pull Request comment same as the below format." lock-pullrequest-aftermerge: false From 95210c0acdb7936b33925254469403506b2aa16d Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Thu, 19 Feb 2026 10:41:08 -0300 Subject: [PATCH 15/50] ci(cla): attempt without `[bot]` suffix --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 8950de2f0a24e831d1dfc340f7cb8adf017394ea..9ae885adc687c452d8a008ef0d0699f25dab05a9 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -29,7 +29,7 @@ jobs: path-to-signatures: ".github/cla-signatures.json" path-to-document: "https://github.com/charmbracelet/crush/blob/main/CLA.md" branch: "main" - allowlist: charmcli,charmcrush,dependabot[bot],copilot-swe-agent[bot] + allowlist: charmcli,charmcrush,dependabot[bot],copilot-swe-agent custom-pr-sign-comment: "I have read the Contributor License Agreement (CLA) and hereby sign the CLA." custom-notsigned-prcomment: "Thank you for your submission. We really appreciate it! Like many open-source projects, we ask that you sign our [Contributor License Agreement](https://github.com/charmbracelet/crush/blob/main/CLA.md) before we can accept your contribution. You can sign the CLA by just posting a Pull Request comment same as the below format." lock-pullrequest-aftermerge: false From cd7e2383a1b289e389320fcea7549f6c6e9a3454 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Thu, 19 Feb 2026 10:45:27 -0300 Subject: [PATCH 16/50] ci(cla): attempt `copilot` --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 9ae885adc687c452d8a008ef0d0699f25dab05a9..3d7d59f1f6728d48e07827f1e8aa43e367854705 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -29,7 +29,7 @@ jobs: path-to-signatures: ".github/cla-signatures.json" path-to-document: "https://github.com/charmbracelet/crush/blob/main/CLA.md" branch: "main" - allowlist: charmcli,charmcrush,dependabot[bot],copilot-swe-agent + allowlist: charmcli,charmcrush,dependabot[bot],copilot custom-pr-sign-comment: "I have read the Contributor License Agreement (CLA) and hereby sign the CLA." custom-notsigned-prcomment: "Thank you for your submission. We really appreciate it! Like many open-source projects, we ask that you sign our [Contributor License Agreement](https://github.com/charmbracelet/crush/blob/main/CLA.md) before we can accept your contribution. You can sign the CLA by just posting a Pull Request comment same as the below format." lock-pullrequest-aftermerge: false From 84fe27be7c9af9a5a415c8e067c1f950fb2f2ec1 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Thu, 19 Feb 2026 10:48:15 -0300 Subject: [PATCH 17/50] ci(cla): try capital letter --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 3d7d59f1f6728d48e07827f1e8aa43e367854705..89c009fb1ce246b0ca04990d9b2281964c8be0fd 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -29,7 +29,7 @@ jobs: path-to-signatures: ".github/cla-signatures.json" path-to-document: "https://github.com/charmbracelet/crush/blob/main/CLA.md" branch: "main" - allowlist: charmcli,charmcrush,dependabot[bot],copilot + allowlist: charmcli,charmcrush,dependabot[bot],Copilot custom-pr-sign-comment: "I have read the Contributor License Agreement (CLA) and hereby sign the CLA." custom-notsigned-prcomment: "Thank you for your submission. We really appreciate it! Like many open-source projects, we ask that you sign our [Contributor License Agreement](https://github.com/charmbracelet/crush/blob/main/CLA.md) before we can accept your contribution. You can sign the CLA by just posting a Pull Request comment same as the below format." lock-pullrequest-aftermerge: false From 9862d3a5552d3246eaff554cca83f2b4eee42ffd Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 10:56:55 -0300 Subject: [PATCH 18/50] fix: address `nil` pointer dereference panics on lsp client methods (#2256) Co-authored-by: andreynering <7011819+andreynering@users.noreply.github.com> --- internal/lsp/client.go | 18 ++++++++++++++++++ internal/lsp/client_test.go | 15 +++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/internal/lsp/client.go b/internal/lsp/client.go index 3d7f07f977b1ef61bd20652d6bdc6a9b3643383a..18bc1ed954acbf4a0397dfa497bd2133513bb090 100644 --- a/internal/lsp/client.go +++ b/internal/lsp/client.go @@ -324,6 +324,9 @@ type OpenFileInfo struct { // HandlesFile checks if this LSP client handles the given file based on its // extension and whether it's within the working directory. func (c *Client) HandlesFile(path string) bool { + if c == nil { + return false + } if !fsext.HasPrefix(path, c.cwd) { slog.Debug("File outside workspace", "name", c.name, "file", path, "workDir", c.cwd) return false @@ -364,6 +367,9 @@ func (c *Client) OpenFile(ctx context.Context, filepath string) error { // NotifyChange notifies the server about a file change. func (c *Client) NotifyChange(ctx context.Context, filepath string) error { + if c == nil { + return nil + } uri := string(protocol.URIFromPath(filepath)) content, err := os.ReadFile(filepath) @@ -420,12 +426,18 @@ func (c *Client) GetFileDiagnostics(uri protocol.DocumentURI) []protocol.Diagnos // GetDiagnostics returns all diagnostics for all files. func (c *Client) GetDiagnostics() map[protocol.DocumentURI][]protocol.Diagnostic { + if c == nil { + return nil + } return c.diagnostics.Copy() } // GetDiagnosticCounts returns cached diagnostic counts by severity. // Uses the VersionedMap version to avoid recomputing on every call. func (c *Client) GetDiagnosticCounts() DiagnosticCounts { + if c == nil { + return DiagnosticCounts{} + } currentVersion := c.diagnostics.Version() c.diagCountsMu.Lock() @@ -459,6 +471,9 @@ func (c *Client) GetDiagnosticCounts() DiagnosticCounts { // OpenFileOnDemand opens a file only if it's not already open. func (c *Client) OpenFileOnDemand(ctx context.Context, filepath string) error { + if c == nil { + return nil + } // Check if the file is already open if c.IsFileOpen(filepath) { return nil @@ -501,6 +516,9 @@ func (c *Client) openKeyConfigFiles(ctx context.Context) { // WaitForDiagnostics waits until diagnostics change or the timeout is reached. func (c *Client) WaitForDiagnostics(ctx context.Context, d time.Duration) { + if c == nil { + return + } ticker := time.NewTicker(200 * time.Millisecond) defer ticker.Stop() timeout := time.After(d) diff --git a/internal/lsp/client_test.go b/internal/lsp/client_test.go index e444354800b6e41ad26a1d8f0d8ffb097a1f060a..62979144babd0abc77006a621301809c997420a4 100644 --- a/internal/lsp/client_test.go +++ b/internal/lsp/client_test.go @@ -3,9 +3,11 @@ package lsp import ( "context" "testing" + "time" "github.com/charmbracelet/crush/internal/config" "github.com/charmbracelet/crush/internal/env" + "github.com/stretchr/testify/require" ) func TestClient(t *testing.T) { @@ -55,3 +57,16 @@ func TestClient(t *testing.T) { t.Logf("Close failed as expected with dummy command: %v", err) } } + +func TestNilClient(t *testing.T) { + t.Parallel() + + var c *Client + + require.False(t, c.HandlesFile("/some/file.go")) + require.Equal(t, DiagnosticCounts{}, c.GetDiagnosticCounts()) + require.Nil(t, c.GetDiagnostics()) + require.Nil(t, c.OpenFileOnDemand(context.Background(), "/some/file.go")) + require.Nil(t, c.NotifyChange(context.Background(), "/some/file.go")) + c.WaitForDiagnostics(context.Background(), time.Second) +} From 46ebd20b63d8e5265e14393821ce747e8ce44ff3 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 19 Feb 2026 17:00:56 +0300 Subject: [PATCH 19/50] fix(ui): optimize assistant message rendering to improve performance (#2258) This commit attempts to fix an issue where the rendering of assistant messages in the chat UI can become significantly degraded in performance, especially for long messages. The root cause of the performance degradation was identified as the use of lipgloss.Render for applying styles to the message content, which involves wrapping logic that can be expensive for long messages. --- internal/ui/chat/assistant.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/internal/ui/chat/assistant.go b/internal/ui/chat/assistant.go index 4ce71dda2515e5489900c33eb716e1d6d884409a..3a727ea7638915c54fac94872d9487fd283f9076 100644 --- a/internal/ui/chat/assistant.go +++ b/internal/ui/chat/assistant.go @@ -107,11 +107,23 @@ func (a *AssistantMessageItem) RawRender(width int) string { // Render implements MessageItem. func (a *AssistantMessageItem) Render(width int) string { - style := a.sty.Chat.Message.AssistantBlurred - if a.focused { - style = a.sty.Chat.Message.AssistantFocused + // XXX: Here, we're manually applying the focused/blurred styles because + // using lipgloss.Render can degrade performance for long messages due to + // it's wrapping logic. + // We already know that the content is wrapped to the correct width in + // RawRender, so we can just apply the styles directly to each line. + focused := a.sty.Chat.Message.AssistantFocused.Render() + blurred := a.sty.Chat.Message.AssistantBlurred.Render() + rendered := a.RawRender(width) + lines := strings.Split(rendered, "\n") + for i, line := range lines { + if a.focused { + lines[i] = focused + line + } else { + lines[i] = blurred + line + } } - return style.Render(a.RawRender(width)) + return strings.Join(lines, "\n") } // renderMessageContent renders the message content including thinking, main content, and finish reason. From 3a7d79fd7b8fe4668b783d83897aa0227e07a96a Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 19 Feb 2026 17:48:08 +0300 Subject: [PATCH 21/50] fix(ci): allow Unlicense in dependency review action (#2259) --- .github/workflows/security.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 29a71ffe1b435ed6a297e16a4912cec89b2e8df3..97f7da89e28917d19d3a1a410fc2e060cafe75f7 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -89,4 +89,4 @@ jobs: - uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2 with: fail-on-severity: critical - allow-licenses: BSD-2-Clause, BSD-3-Clause, MIT, Apache-2.0, MPL-2.0, ISC, LicenseRef-scancode-google-patent-license-golang + allow-licenses: BSD-2-Clause, BSD-3-Clause, MIT, Apache-2.0, MPL-2.0, ISC, LicenseRef-scancode-google-patent-license-golang, Unlicense From 0a2a3feb6da2f665e5d590736bc28fce1bd1d38b Mon Sep 17 00:00:00 2001 From: Austin Cherry Date: Fri, 20 Feb 2026 07:09:32 -0600 Subject: [PATCH 22/50] fix(lsp): prevent nil client from being stored in clients map (#2262) --- internal/lsp/manager.go | 42 +++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/internal/lsp/manager.go b/internal/lsp/manager.go index 44f04e9a6e005a9217b4f62e3f3b477f1ff85838..d6b1eaba5498b71c59566c2fbb1df642b6335c6d 100644 --- a/internal/lsp/manager.go +++ b/internal/lsp/manager.go @@ -178,24 +178,38 @@ func (s *Manager) startServer(ctx context.Context, name, filepath string, server return } - // check again in case another goroutine started it in the meantime - var err error - client := s.clients.GetOrSet(name, func() *Client { - var cli *Client - cli, err = New( - ctx, - name, - cfg, - s.cfg.Resolver(), - s.cfg.WorkingDir(), - s.cfg.Options.DebugLSP, - ) - return cli - }) + // Check again in case another goroutine started it in the meantime. + if client, ok := s.clients.Get(name); ok { + switch client.GetServerState() { + case StateReady, StateStarting, StateDisabled: + s.callback(name, client) + return + } + } + + client, err := New( + ctx, + name, + cfg, + s.cfg.Resolver(), + s.cfg.WorkingDir(), + s.cfg.Options.DebugLSP, + ) if err != nil { slog.Error("Failed to create LSP client", "name", name, "error", err) return } + // Only store non-nil clients. If another goroutine raced us, + // prefer the already-stored client. + if existing, ok := s.clients.Get(name); ok { + switch existing.GetServerState() { + case StateReady, StateStarting, StateDisabled: + client.Close(ctx) + s.callback(name, existing) + return + } + } + s.clients.Set(name, client) defer func() { s.callback(name, client) }() From dcf03db072bcb1f7f067c35b889f7411517c94f1 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Fri, 20 Feb 2026 10:44:53 -0300 Subject: [PATCH 23/50] refactor: simply code --- internal/config/load.go | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/internal/config/load.go b/internal/config/load.go index 077598509796fa13b47dd0e0f05a3dbaeb4975db..3fba44aa9142c52b8966b1dbe994cef0ae654c48 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -219,15 +219,19 @@ func (c *Config) configureProviders(env env.Env, resolver VariableResolver, know switch p.ID { // Handle specific providers that require additional configuration case catwalk.InferenceProviderVertexAI: - if !hasVertexCredentials(env) { + var ( + project = env.Get("VERTEXAI_PROJECT") + location = env.Get("VERTEXAI_LOCATION") + ) + if project == "" || location == "" { if configExists { slog.Warn("Skipping Vertex AI provider due to missing credentials") c.Providers.Del(string(p.ID)) } continue } - prepared.ExtraParams["project"] = env.Get("VERTEXAI_PROJECT") - prepared.ExtraParams["location"] = env.Get("VERTEXAI_LOCATION") + prepared.ExtraParams["project"] = project + prepared.ExtraParams["location"] = location case catwalk.InferenceProviderAzure: endpoint, err := resolver.ResolveValue(p.APIEndpoint) if err != nil || endpoint == "" { @@ -677,12 +681,6 @@ func loadFromBytes(configs [][]byte) (*Config, error) { return &config, nil } -func hasVertexCredentials(env env.Env) bool { - hasProject := env.Get("VERTEXAI_PROJECT") != "" - hasLocation := env.Get("VERTEXAI_LOCATION") != "" - return hasProject && hasLocation -} - func hasAWSCredentials(env env.Env) bool { if env.Get("AWS_BEARER_TOKEN_BEDROCK") != "" { return true From 4ba7e02629a934442d49796038cb45f3fa21ee2d Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Fri, 20 Feb 2026 13:42:50 -0300 Subject: [PATCH 24/50] ci: update to go 1.26 stable for govulncheck --- .github/workflows/security.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 97f7da89e28917d19d3a1a410fc2e060cafe75f7..bf1931c79e8576125f608157e36c5747ee25369e 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -67,7 +67,7 @@ jobs: persist-credentials: false - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 with: - go-version: 1.26.0-rc.1 # change to "stable" once Go 1.26 is released + go-version: 1.26.0 - name: Install govulncheck run: go install golang.org/x/vuln/cmd/govulncheck@latest - name: Run govulncheck From d699acd115e7024982753606ffa73887cb14523b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 16:43:25 +0000 Subject: [PATCH 25/50] chore(deps): bump the all group with 2 updates (#2271) Bumps the all group with 2 updates: [github/codeql-action](https://github.com/github/codeql-action) and [actions/dependency-review-action](https://github.com/actions/dependency-review-action). Updates `github/codeql-action` from 4.32.3 to 4.32.4 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/9e907b5e64f6b83e7804b09294d44122997950d6...89a39a4e59826350b863aa6b6252a07ad50cf83e) Updates `actions/dependency-review-action` from 4.8.2 to 4.8.3 - [Release notes](https://github.com/actions/dependency-review-action/releases) - [Commits](https://github.com/actions/dependency-review-action/compare/3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261...05fe4576374b728f0c523d6a13d64c25081e0803) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.32.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all - dependency-name: actions/dependency-review-action dependency-version: 4.8.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/security.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index bf1931c79e8576125f608157e36c5747ee25369e..0ec626008218192017791edf82972bcae57b0a5f 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -30,11 +30,11 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - uses: github/codeql-action/init@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 + - uses: github/codeql-action/init@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 with: languages: ${{ matrix.language }} - - uses: github/codeql-action/autobuild@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 - - uses: github/codeql-action/analyze@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 + - uses: github/codeql-action/autobuild@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 + - uses: github/codeql-action/analyze@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 grype: runs-on: ubuntu-latest @@ -52,7 +52,7 @@ jobs: path: "." fail-build: true severity-cutoff: critical - - uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 + - uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 with: sarif_file: ${{ steps.scan.outputs.sarif }} @@ -73,7 +73,7 @@ jobs: - name: Run govulncheck run: | govulncheck -C . -format sarif ./... > results.sarif - - uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3 + - uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 with: sarif_file: results.sarif @@ -86,7 +86,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2 + - uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4.8.3 with: fail-on-severity: critical allow-licenses: BSD-2-Clause, BSD-3-Clause, MIT, Apache-2.0, MPL-2.0, ISC, LicenseRef-scancode-google-patent-license-golang, Unlicense From ac0972b48b4f5d6710fa9cae6680683ba18647a7 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Fri, 20 Feb 2026 13:44:04 -0300 Subject: [PATCH 26/50] fix: use `Authorization` header for MiniMax (#2269) Co-authored-by: Greg Slepak --- internal/agent/coordinator.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/internal/agent/coordinator.go b/internal/agent/coordinator.go index a1fd6ae3dd293cac5ad65079c96bad4acd47c4f9..5acafb993d2d40860ae1ccf3992dea9c3e1b7980 100644 --- a/internal/agent/coordinator.go +++ b/internal/agent/coordinator.go @@ -566,14 +566,19 @@ func (c *coordinator) buildAgentModels(ctx context.Context, isSubAgent bool) (Mo }, nil } -func (c *coordinator) buildAnthropicProvider(baseURL, apiKey string, headers map[string]string) (fantasy.Provider, error) { +func (c *coordinator) buildAnthropicProvider(baseURL, apiKey string, headers map[string]string, providerID string) (fantasy.Provider, error) { var opts []anthropic.Option - if strings.HasPrefix(apiKey, "Bearer ") { + switch { + case strings.HasPrefix(apiKey, "Bearer "): // NOTE: Prevent the SDK from picking up the API key from env. os.Setenv("ANTHROPIC_API_KEY", "") headers["Authorization"] = apiKey - } else if apiKey != "" { + case providerID == string(catwalk.InferenceProviderMiniMax): + // NOTE: Prevent the SDK from picking up the API key from env. + os.Setenv("ANTHROPIC_API_KEY", "") + headers["Authorization"] = "Bearer " + apiKey + case apiKey != "": // X-Api-Key header opts = append(opts, anthropic.WithAPIKey(apiKey)) } @@ -793,7 +798,7 @@ func (c *coordinator) buildProvider(providerCfg config.ProviderConfig, model con case openai.Name: return c.buildOpenaiProvider(baseURL, apiKey, headers) case anthropic.Name: - return c.buildAnthropicProvider(baseURL, apiKey, headers) + return c.buildAnthropicProvider(baseURL, apiKey, headers, providerCfg.ID) case openrouter.Name: return c.buildOpenrouterProvider(baseURL, apiKey, headers) case vercel.Name: From a189a3d1ffcfe3afb27355552229f1af0c5cd9f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 16:49:31 +0000 Subject: [PATCH 27/50] chore(deps): bump the all group across 1 directory with 7 updates (#2270) Bumps the all group with 6 updates in the / directory: | Package | From | To | | --- | --- | --- | | [charm.land/catwalk](https://github.com/charmbracelet/catwalk) | `0.19.2` | `0.20.2` | | [charm.land/fantasy](https://github.com/charmbracelet/fantasy) | `0.8.1` | `0.9.0` | | [github.com/aymanbagabas/go-udiff](https://github.com/aymanbagabas/go-udiff) | `0.3.1` | `0.4.0` | | [github.com/clipperhouse/uax29/v2](https://github.com/clipperhouse/uax29) | `2.6.0` | `2.7.0` | | [github.com/modelcontextprotocol/go-sdk](https://github.com/modelcontextprotocol/go-sdk) | `1.2.0` | `1.3.1` | | [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) | `1.44.3` | `1.46.1` | Updates `charm.land/catwalk` from 0.19.2 to 0.20.2 - [Release notes](https://github.com/charmbracelet/catwalk/releases) - [Commits](https://github.com/charmbracelet/catwalk/compare/v0.19.2...v0.20.2) Updates `charm.land/fantasy` from 0.8.1 to 0.9.0 - [Release notes](https://github.com/charmbracelet/fantasy/releases) - [Commits](https://github.com/charmbracelet/fantasy/compare/v0.8.1...v0.9.0) Updates `github.com/aymanbagabas/go-udiff` from 0.3.1 to 0.4.0 - [Release notes](https://github.com/aymanbagabas/go-udiff/releases) - [Commits](https://github.com/aymanbagabas/go-udiff/compare/v0.3.1...v0.4.0) Updates `github.com/clipperhouse/uax29/v2` from 2.6.0 to 2.7.0 - [Release notes](https://github.com/clipperhouse/uax29/releases) - [Commits](https://github.com/clipperhouse/uax29/compare/v2.6.0...v2.7.0) Updates `github.com/modelcontextprotocol/go-sdk` from 1.2.0 to 1.3.1 - [Release notes](https://github.com/modelcontextprotocol/go-sdk/releases) - [Commits](https://github.com/modelcontextprotocol/go-sdk/compare/v1.2.0...v1.3.1) Updates `golang.org/x/net` from 0.49.0 to 0.50.0 - [Commits](https://github.com/golang/net/compare/v0.49.0...v0.50.0) Updates `modernc.org/sqlite` from 1.44.3 to 1.46.1 - [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md) - [Commits](https://gitlab.com/cznic/sqlite/compare/v1.44.3...v1.46.1) --- updated-dependencies: - dependency-name: charm.land/catwalk dependency-version: 0.20.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all - dependency-name: charm.land/fantasy dependency-version: 0.9.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all - dependency-name: github.com/aymanbagabas/go-udiff dependency-version: 0.4.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all - dependency-name: github.com/clipperhouse/uax29/v2 dependency-version: 2.7.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all - dependency-name: github.com/modelcontextprotocol/go-sdk dependency-version: 1.3.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all - dependency-name: golang.org/x/net dependency-version: 0.50.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all - dependency-name: modernc.org/sqlite dependency-version: 1.46.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 79 ++++++++++++------------- go.sum | 182 +++++++++++++++++++++++++++++---------------------------- 2 files changed, 133 insertions(+), 128 deletions(-) diff --git a/go.mod b/go.mod index c61066077cd1b60fe93c6875b42e9301a1785d85..5d12422d5f45ce34a344d09a4b0b01d62feb0d61 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,12 @@ module github.com/charmbracelet/crush -go 1.25.5 +go 1.26.0 require ( charm.land/bubbles/v2 v2.0.0-rc.1.0.20260109112849-ae99f46cec66 charm.land/bubbletea/v2 v2.0.0-rc.2.0.20260209074636-30878e43d7b0 - charm.land/catwalk v0.19.2 - charm.land/fantasy v0.8.1 + charm.land/catwalk v0.20.2 + charm.land/fantasy v0.9.0 charm.land/glamour/v2 v2.0.0-20260123212943-6014aa153a9b charm.land/lipgloss/v2 v2.0.0-beta.3.0.20260212100304-e18737634dea charm.land/log/v2 v2.0.0-20251110204020-529bb77f35da @@ -17,7 +17,7 @@ require ( github.com/alecthomas/chroma/v2 v2.23.1 github.com/atotto/clipboard v0.1.4 github.com/aymanbagabas/go-nativeclipboard v0.1.3 - github.com/aymanbagabas/go-udiff v0.3.1 + github.com/aymanbagabas/go-udiff v0.4.0 github.com/bmatcuk/doublestar/v4 v4.10.0 github.com/charlievieth/fastwalk v1.0.14 github.com/charmbracelet/colorprofile v0.4.2 @@ -34,7 +34,7 @@ require ( github.com/charmbracelet/x/powernap v0.0.0-20260209132835-6b065b8ba62c github.com/charmbracelet/x/term v0.2.2 github.com/clipperhouse/displaywidth v0.10.0 - github.com/clipperhouse/uax29/v2 v2.6.0 + github.com/clipperhouse/uax29/v2 v2.7.0 github.com/denisbrodbeck/machineid v1.0.1 github.com/disintegration/imaging v1.6.2 github.com/dustin/go-humanize v1.0.1 @@ -45,7 +45,7 @@ require ( github.com/jordanella/go-ansi-paintbrush v0.0.0-20240728195301-b7ad996ecf3d github.com/lucasb-eyer/go-colorful v1.3.0 github.com/mattn/go-isatty v0.0.20 - github.com/modelcontextprotocol/go-sdk v1.2.0 + github.com/modelcontextprotocol/go-sdk v1.3.1 github.com/ncruces/go-sqlite3 v0.30.5 github.com/nxadm/tail v1.4.11 github.com/openai/openai-go/v2 v2.7.1 @@ -62,28 +62,28 @@ require ( github.com/tidwall/sjson v1.2.5 github.com/zeebo/xxh3 v1.1.0 go.uber.org/goleak v1.3.0 - golang.org/x/net v0.49.0 + golang.org/x/net v0.50.0 golang.org/x/sync v0.19.0 golang.org/x/text v0.34.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 - modernc.org/sqlite v1.44.3 + modernc.org/sqlite v1.46.1 mvdan.cc/sh/moreinterp v0.0.0-20250902163504-3cf4fd5717a5 mvdan.cc/sh/v3 v3.12.1-0.20250902163504-3cf4fd5717a5 ) require ( - cloud.google.com/go v0.116.0 // indirect - cloud.google.com/go/auth v0.18.1 // indirect + cloud.google.com/go v0.123.0 // indirect + cloud.google.com/go/auth v0.18.2 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/andybalholm/cascadia v1.3.3 // indirect github.com/aws/aws-sdk-go-v2 v1.41.1 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect - github.com/aws/aws-sdk-go-v2/config v1.32.7 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.19.7 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect + github.com/aws/aws-sdk-go-v2/config v1.32.9 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.9 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect @@ -91,8 +91,8 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.10 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect github.com/aws/smithy-go v1.24.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect @@ -103,8 +103,7 @@ require ( github.com/charmbracelet/x/json v0.2.0 // indirect github.com/charmbracelet/x/termios v0.1.1 // indirect github.com/charmbracelet/x/windows v0.2.2 // indirect - github.com/clipperhouse/stringish v0.1.1 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dlclark/regexp2 v1.11.5 // indirect github.com/ebitengine/purego v0.10.0-alpha.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -120,20 +119,20 @@ require ( github.com/goccy/go-yaml v1.19.2 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/jsonschema-go v0.3.0 // indirect + github.com/google/jsonschema-go v0.4.2 // indirect github.com/google/s2a-go v0.1.9 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect - github.com/googleapis/gax-go/v2 v2.15.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.12 // indirect + github.com/googleapis/gax-go/v2 v2.17.0 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/kaptinlin/go-i18n v0.2.3 // indirect - github.com/kaptinlin/jsonpointer v0.4.9 // indirect - github.com/kaptinlin/jsonschema v0.6.10 // indirect - github.com/kaptinlin/messageformat-go v0.4.9 // indirect - github.com/klauspost/compress v1.18.0 // indirect + github.com/kaptinlin/go-i18n v0.2.9 // indirect + github.com/kaptinlin/jsonpointer v0.4.16 // indirect + github.com/kaptinlin/jsonschema v0.7.2 // indirect + github.com/kaptinlin/messageformat-go v0.4.18 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -149,8 +148,10 @@ require ( github.com/ncruces/go-strftime v1.0.0 // indirect github.com/ncruces/julianday v1.0.0 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/segmentio/asm v1.2.0 // indirect + github.com/segmentio/encoding v0.5.3 // indirect github.com/sethvargo/go-retry v0.3.0 // indirect github.com/spf13/pflag v1.0.9 // indirect github.com/tetratelabs/wazero v1.11.0 // indirect @@ -164,25 +165,25 @@ require ( github.com/yuin/goldmark v1.7.8 // indirect github.com/yuin/goldmark-emoji v1.0.5 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect - go.opentelemetry.io/otel v1.39.0 // indirect - go.opentelemetry.io/otel/metric v1.39.0 // indirect - go.opentelemetry.io/otel/trace v1.39.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect + go.opentelemetry.io/otel v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.40.0 // indirect + go.opentelemetry.io/otel/trace v1.40.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v4 v4.0.0-rc.3 // indirect - golang.org/x/crypto v0.47.0 // indirect - golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect + golang.org/x/crypto v0.48.0 // indirect + golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a // indirect golang.org/x/image v0.36.0 // indirect golang.org/x/oauth2 v0.35.0 // indirect golang.org/x/sys v0.41.0 // indirect - golang.org/x/term v0.39.0 // indirect + golang.org/x/term v0.40.0 // indirect golang.org/x/time v0.14.0 // indirect - google.golang.org/api v0.239.0 // indirect - google.golang.org/genai v1.45.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect - google.golang.org/grpc v1.76.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/api v0.266.0 // indirect + google.golang.org/genai v1.47.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect + google.golang.org/grpc v1.79.1 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/dnaeon/go-vcr.v4 v4.0.6-0.20251110073552-01de4eb40290 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff --git a/go.sum b/go.sum index 2f1d09ae6a8b4a2afa1dc391abce8cf4651519e0..7707492dc4c960535f6d043546f52103c2f6c0c7 100644 --- a/go.sum +++ b/go.sum @@ -2,10 +2,10 @@ charm.land/bubbles/v2 v2.0.0-rc.1.0.20260109112849-ae99f46cec66 h1:2BdJynsAW+8rv charm.land/bubbles/v2 v2.0.0-rc.1.0.20260109112849-ae99f46cec66/go.mod h1:5AbN6cEd/47gkEf8TgiQ2O3RZ5QxMS14l9W+7F9fPC4= charm.land/bubbletea/v2 v2.0.0-rc.2.0.20260209074636-30878e43d7b0 h1:HAbpM9TPjZM18D677ww3VnkKXdd2hyMQtHUsVV0HcPQ= charm.land/bubbletea/v2 v2.0.0-rc.2.0.20260209074636-30878e43d7b0/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ= -charm.land/catwalk v0.19.2 h1:exy+egllV6VEuR0e5eGkefnL6xnlszNxy9FpH2vjss4= -charm.land/catwalk v0.19.2/go.mod h1:rFC/V96rIHX7VES215c/qzI1EW/Moo1ggs1Q6seTy5s= -charm.land/fantasy v0.8.1 h1:2zQovDrd26g+/X2+/6bMomTX54HmZWNNHWeorDO0WRo= -charm.land/fantasy v0.8.1/go.mod h1:KJ8vjy9FH7G2aeR/fL+os2uFHkQ4js2+UJVbsUKCXYM= +charm.land/catwalk v0.20.2 h1:QVawbjbw1UjLdQAUEarufOd0m6Lze+9sYwxlrrNemYo= +charm.land/catwalk v0.20.2/go.mod h1:rFC/V96rIHX7VES215c/qzI1EW/Moo1ggs1Q6seTy5s= +charm.land/fantasy v0.9.0 h1:2KzDYZC3IDb6T8KhWn4akqDHoU5Evr+VwL2xbaWtXmM= +charm.land/fantasy v0.9.0/go.mod h1:vpR/vcgCtKZ5SWHNbW/5c1b+DMDNNO15j+t/evoQb/4= charm.land/glamour/v2 v2.0.0-20260123212943-6014aa153a9b h1:A6IUUyChZDWP16RUdRJCfmYISAKWQGyIcfhZJUCViQ0= charm.land/glamour/v2 v2.0.0-20260123212943-6014aa153a9b/go.mod h1:J3kVhY6oHXZq5f+8vC3hmDO95fEvbqj3z7xDwxrfzU8= charm.land/lipgloss/v2 v2.0.0-beta.3.0.20260212100304-e18737634dea h1:XBmpGhIKPN8o9VjuXg+X5WXFsEqUs/YtPx0Q0zzmTTA= @@ -14,10 +14,10 @@ charm.land/log/v2 v2.0.0-20251110204020-529bb77f35da h1:vZa/Ow0uLclpfaDY0ubjzE+B charm.land/log/v2 v2.0.0-20251110204020-529bb77f35da/go.mod h1:Tj12StbPc4GwksDF6XwhC9wdXouinIVxRGKKmmmzdSU= charm.land/x/vcr v0.1.1 h1:PXCFMUG0rPtyk35rhfzYCJEduOzWXCIbrXTFq4OF/9Q= charm.land/x/vcr v0.1.1/go.mod h1:eByq2gqzWvcct/8XE2XO5KznoWEBiXH56+y2gphbltM= -cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= -cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go/auth v0.18.1 h1:IwTEx92GFUo2pJ6Qea0EU3zYvKnTAeRCODxfA/G5UWs= -cloud.google.com/go/auth v0.18.1/go.mod h1:GfTYoS9G3CWpRA3Va9doKN9mjPGRS+v41jmZAhBzbrA= +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= +cloud.google.com/go/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM= +cloud.google.com/go/auth v0.18.2/go.mod h1:xD+oY7gcahcu7G2SG2DsBerfFxgPAJz17zz2joOFF3M= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= @@ -50,12 +50,12 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU= github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM= -github.com/aws/aws-sdk-go-v2/config v1.32.7 h1:vxUyWGUwmkQ2g19n7JY/9YL8MfAIl7bTesIUykECXmY= -github.com/aws/aws-sdk-go-v2/config v1.32.7/go.mod h1:2/Qm5vKUU/r7Y+zUk/Ptt2MDAEKAfUtKc1+3U1Mo3oY= -github.com/aws/aws-sdk-go-v2/credentials v1.19.7 h1:tHK47VqqtJxOymRrNtUXN5SP/zUTvZKeLx4tH6PGQc8= -github.com/aws/aws-sdk-go-v2/credentials v1.19.7/go.mod h1:qOZk8sPDrxhf+4Wf4oT2urYJrYt3RejHSzgAquYeppw= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4= +github.com/aws/aws-sdk-go-v2/config v1.32.9 h1:ktda/mtAydeObvJXlHzyGpK1xcsLaP16zfUPDGoW90A= +github.com/aws/aws-sdk-go-v2/config v1.32.9/go.mod h1:U+fCQ+9QKsLW786BCfEjYRj34VVTbPdsLP3CHSYXMOI= +github.com/aws/aws-sdk-go-v2/credentials v1.19.9 h1:sWvTKsyrMlJGEuj/WgrwilpoJ6Xa1+KhIpGdzw7mMU8= +github.com/aws/aws-sdk-go-v2/credentials v1.19.9/go.mod h1:+J44MBhmfVY/lETFiKI+klz0Vym2aCmIjqgClMmW82w= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U= @@ -70,18 +70,18 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMooz github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU= github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y= github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.9/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 h1:gd84Omyu9JLriJVCbGApcLzVR3XtmC4ZDPcAI6Ftvds= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.10 h1:+VTRawC4iVY58pS/lzpo0lnoa/SYNGF4/B/3/U5ro8Y= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.10/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14 h1:0jbJeuEHlwKJ9PfXtpSFc4MF+WIWORdhN1n30ITZGFM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo= github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ= github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ= github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/aymanbagabas/go-nativeclipboard v0.1.3 h1:FmAWHPTwneAixu7uGDn3cL42xPlUCdNp2J8egMn3P1k= github.com/aymanbagabas/go-nativeclipboard v0.1.3/go.mod h1:2o7MyZwwi4pmXXpOpvOS5FwaHyoCIUks0ktjUvB0EoE= -github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY= -github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E= +github.com/aymanbagabas/go-udiff v0.4.0 h1:TKnLPh7IbnizJIBKFWa9mKayRUBQ9Kh1BPCk6w2PnYM= +github.com/aymanbagabas/go-udiff v0.4.0/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= @@ -130,18 +130,17 @@ github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2 github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k= github.com/clipperhouse/displaywidth v0.10.0 h1:GhBG8WuerxjFQQYeuZAeVTuyxuX+UraiZGD4HJQ3Y8g= github.com/clipperhouse/displaywidth v0.10.0/go.mod h1:XqJajYsaiEwkxOj4bowCTMcT1SgvHo9flfF3jQasdbs= -github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= -github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= -github.com/clipperhouse/uax29/v2 v2.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos= -github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= -github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= -github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= +github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik= +github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ= github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= @@ -152,11 +151,11 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/ebitengine/purego v0.10.0-alpha.4 h1:JzPbdf+cqbyT9sZtP4xnqelwUXwf7LvD8xKS6+ofTds= github.com/ebitengine/purego v0.10.0-alpha.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= -github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= -github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= -github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= -github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= -github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g= +github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98= +github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4= +github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= @@ -194,18 +193,18 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q= -github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= +github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8= +github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.7 h1:zrn2Ee/nWmHulBx5sAVrGgAa0f2/R35S4DJwfFaUPFQ= -github.com/googleapis/enterprise-certificate-proxy v0.3.7/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= -github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= -github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= +github.com/googleapis/enterprise-certificate-proxy v0.3.12 h1:Fg+zsqzYEs1ZnvmcztTYxhgCBsx3eEhEwQ1W/lHq/sQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.12/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg= +github.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ1J6SMc= +github.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY= github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -226,16 +225,16 @@ github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA github.com/jordanella/go-ansi-paintbrush v0.0.0-20240728195301-b7ad996ecf3d h1:on25kP+Sx7sxUMRQiA8gdcToAGet4DK/EIA30mXre+4= github.com/jordanella/go-ansi-paintbrush v0.0.0-20240728195301-b7ad996ecf3d/go.mod h1:SV0W0APWP9MZ1/gfDQ/NzzTlWdIgYZ/ZbpN4d/UXRYw= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kaptinlin/go-i18n v0.2.3 h1:jyN/YOXXLcnGRBLdU+a8+6782B97fWE5aQqAHtvvk8Q= -github.com/kaptinlin/go-i18n v0.2.3/go.mod h1:O+Ax4HkMO0Jt4OaP4E4WCx0PAADeWkwk8Jgt9bjAU1w= -github.com/kaptinlin/jsonpointer v0.4.9 h1:o//bYf4PCvnMJIIX8bIg77KB6DO3wBPAabRyPRKh680= -github.com/kaptinlin/jsonpointer v0.4.9/go.mod h1:9y0LgXavlmVE5FSHShY5LRlURJJVhbyVJSRWkilrTqA= -github.com/kaptinlin/jsonschema v0.6.10 h1:CYded7nrwVu7pU1GaIjtd9dSzgqZjh7+LTKFaWqS08I= -github.com/kaptinlin/jsonschema v0.6.10/go.mod h1:ZXZ4K5KrRmCCF1i6dgvBsQifl+WTb8XShKj0NpQNrz8= -github.com/kaptinlin/messageformat-go v0.4.9 h1:FR5j5n4aL4nG0afKn9vvANrKxLu7HjmbhJnw5ogIwAQ= -github.com/kaptinlin/messageformat-go v0.4.9/go.mod h1:qZzrGrlvWDz2KyyvN3dOWcK9PVSRV1BnfnNU+zB/RWc= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/kaptinlin/go-i18n v0.2.9 h1:96TWNQI0j5nPhcmeFaCyX8SfyNhA0CTjeilLTy7ol9M= +github.com/kaptinlin/go-i18n v0.2.9/go.mod h1:Sm0GTLS6hbFDrUQahycQfHF377WR9VF5eDgWrwljCAk= +github.com/kaptinlin/jsonpointer v0.4.16 h1:Ux4w4FY+uLv+K+TxaCJtM/TpPv+1+eS6gH4Z9/uhOuA= +github.com/kaptinlin/jsonpointer v0.4.16/go.mod h1:SsfsjqnHG5zuKo1DTBzk1VknaHlL4osHw+X9kZKukpU= +github.com/kaptinlin/jsonschema v0.7.2 h1:I4AiYZ/be3gtWi4Mb7vtY8W6zN6f4YvT2eHCUXXJfmQ= +github.com/kaptinlin/jsonschema v0.7.2/go.mod h1:Y6SZ/x3m9LZzEQY/NxCjHCmBPprBGMLWZDX3mFN0lJQ= +github.com/kaptinlin/messageformat-go v0.4.18 h1:RBlHVWgZyoxTcUgGWBsl2AcyScq/urqbLZvzgryTmSI= +github.com/kaptinlin/messageformat-go v0.4.18/go.mod h1:ntI3154RnqJgr7GaC+vZBnIExl2V3sv9selvRNNEM24= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= @@ -263,8 +262,8 @@ github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwX github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modelcontextprotocol/go-sdk v1.2.0 h1:Y23co09300CEk8iZ/tMxIX1dVmKZkzoSBZOpJwUnc/s= -github.com/modelcontextprotocol/go-sdk v1.2.0/go.mod h1:6fM3LCm3yV7pAs8isnKLn07oKtB0MP9LHd3DfAcKw10= +github.com/modelcontextprotocol/go-sdk v1.3.1 h1:TfqtNKOIWN4Z1oqmPAiWDC2Jq7K9OdJaooe0teoXASI= +github.com/modelcontextprotocol/go-sdk v1.3.1/go.mod h1:DgVX498dMD8UJlseK1S5i1T4tFz2fkBk4xogC3D15nw= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/mango v0.1.0 h1:DZQK45d2gGbql1arsYA4vfg4d7I9Hfx5rX/GCmzsAvI= @@ -296,8 +295,9 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posthog/posthog-go v1.10.0 h1:wfoy7Jfb4LigCoHYyMZoiJmmEoCLOkSaYfDxM/NtCqY= github.com/posthog/posthog-go v1.10.0/go.mod h1:wB3/9Q7d9gGb1P/yf/Wri9VBlbP8oA8z++prRzL5OcY= github.com/pressly/goose/v3 v3.26.0 h1:KJakav68jdH0WDvoAcj8+n61WqOIaPGgH0bJWS6jpmM= @@ -315,6 +315,10 @@ github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y= github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w= +github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= @@ -366,20 +370,20 @@ github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= -go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= -go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= -go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= -go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= -go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= -go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= -go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= -go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= -go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= -go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 h1:XmiuHzgJt067+a6kwyAzkhXooYVv3/TOw9cM2VfJgUM= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0/go.mod h1:KDgtbWKTQs4bM+VPUr6WlL9m/WXcmkCcBlIzqxPGzmI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0= +go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= +go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= +go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= +go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= +go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= +go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= +go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= +go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= +go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -394,10 +398,10 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= -golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= -golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= -golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o= +golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc= golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4= @@ -406,8 +410,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= -golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -419,8 +423,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -461,8 +465,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= -golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= -golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -482,21 +486,21 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= -golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/api v0.239.0 h1:2hZKUnFZEy81eugPs4e2XzIJ5SOwQg0G82bpXD65Puo= -google.golang.org/api v0.239.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= -google.golang.org/genai v1.45.0 h1:s80ZpS42XW0zu/ogiOtenCio17nJ7reEFJjoCftukpA= -google.golang.org/genai v1.45.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A= -google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/api v0.266.0 h1:hco+oNCf9y7DmLeAtHJi/uBAY7n/7XC9mZPxu1ROiyk= +google.golang.org/api v0.266.0/go.mod h1:Jzc0+ZfLnyvXma3UtaTl023TdhZu6OMBP9tJ+0EmFD0= +google.golang.org/genai v1.47.0 h1:iWCS7gEdO6rctOqfCYLOrZGKu2D+N42aTnCEcBvB1jo= +google.golang.org/genai v1.47.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY= +google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -536,8 +540,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.44.3 h1:+39JvV/HWMcYslAwRxHb8067w+2zowvFOUrOWIy9PjY= -modernc.org/sqlite v1.44.3/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA= +modernc.org/sqlite v1.46.1 h1:eFJ2ShBLIEnUWlLy12raN0Z1plqmFX9Qe3rjQTKt6sU= +modernc.org/sqlite v1.46.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= From f89a9d809ebb10225f351582b916f9ba2578a0ed Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Fri, 20 Feb 2026 14:09:17 -0300 Subject: [PATCH 28/50] fix: proper validate io.net api keys (#2272) They changed the `/models` endpoint so it actually validates the API key header if given. --- internal/config/config.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 626fbe327491eb28d41e2972c3cb221b1deeb0c6..753151509315545dfbed9bd74c1455785313c8aa 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -799,11 +799,6 @@ func (c *ProviderConfig) TestConnection(resolver VariableResolver) error { return fmt.Errorf("invalid API key format for provider %s", c.ID) } return nil - case catwalk.InferenceProviderIoNet: - if !strings.HasPrefix(apiKey, "io-") { - return fmt.Errorf("invalid API key format for provider %s", c.ID) - } - return nil } switch c.Type { From 9e31414aa333f33842fde3271d25861583dfa73b Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Fri, 20 Feb 2026 14:12:52 -0300 Subject: [PATCH 29/50] chore(deps): bump catwalk --- go.mod | 3 ++- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 5d12422d5f45ce34a344d09a4b0b01d62feb0d61..52ba10616772c6f0c18e47944a9c384e156ec90d 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.26.0 require ( charm.land/bubbles/v2 v2.0.0-rc.1.0.20260109112849-ae99f46cec66 charm.land/bubbletea/v2 v2.0.0-rc.2.0.20260209074636-30878e43d7b0 - charm.land/catwalk v0.20.2 + charm.land/catwalk v0.21.0 charm.land/fantasy v0.9.0 charm.land/glamour/v2 v2.0.0-20260123212943-6014aa153a9b charm.land/lipgloss/v2 v2.0.0-beta.3.0.20260212100304-e18737634dea @@ -117,6 +117,7 @@ require ( github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-yaml v1.19.2 // indirect + github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/jsonschema-go v0.4.2 // indirect diff --git a/go.sum b/go.sum index 7707492dc4c960535f6d043546f52103c2f6c0c7..76611757eb1d223ee711b4b5b8b0953d12050868 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ charm.land/bubbles/v2 v2.0.0-rc.1.0.20260109112849-ae99f46cec66 h1:2BdJynsAW+8rv charm.land/bubbles/v2 v2.0.0-rc.1.0.20260109112849-ae99f46cec66/go.mod h1:5AbN6cEd/47gkEf8TgiQ2O3RZ5QxMS14l9W+7F9fPC4= charm.land/bubbletea/v2 v2.0.0-rc.2.0.20260209074636-30878e43d7b0 h1:HAbpM9TPjZM18D677ww3VnkKXdd2hyMQtHUsVV0HcPQ= charm.land/bubbletea/v2 v2.0.0-rc.2.0.20260209074636-30878e43d7b0/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ= -charm.land/catwalk v0.20.2 h1:QVawbjbw1UjLdQAUEarufOd0m6Lze+9sYwxlrrNemYo= -charm.land/catwalk v0.20.2/go.mod h1:rFC/V96rIHX7VES215c/qzI1EW/Moo1ggs1Q6seTy5s= +charm.land/catwalk v0.21.0 h1:ShexIXWiyFH9QOV9EqQikUUdrvidiFm8PYXGl9Ql6VA= +charm.land/catwalk v0.21.0/go.mod h1:rFC/V96rIHX7VES215c/qzI1EW/Moo1ggs1Q6seTy5s= charm.land/fantasy v0.9.0 h1:2KzDYZC3IDb6T8KhWn4akqDHoU5Evr+VwL2xbaWtXmM= charm.land/fantasy v0.9.0/go.mod h1:vpR/vcgCtKZ5SWHNbW/5c1b+DMDNNO15j+t/evoQb/4= charm.land/glamour/v2 v2.0.0-20260123212943-6014aa153a9b h1:A6IUUyChZDWP16RUdRJCfmYISAKWQGyIcfhZJUCViQ0= @@ -184,8 +184,8 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= -github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= From c43192c80b2cab8860fc533eb8456a14bb76ebc1 Mon Sep 17 00:00:00 2001 From: 0xarcher Date: Sat, 21 Feb 2026 01:22:16 +0800 Subject: [PATCH 30/50] fix(agent): pass correct model config to small provider builder (#2236) When building the small model provider, we were incorrectly passing largeModelCfg instead of smallModelCfg to buildProvider. This caused isAnthropicThinking to check the wrong model config, preventing the small model from enabling Anthropic thinking mode even when configured. Fixes #2141 --- internal/agent/coordinator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/agent/coordinator.go b/internal/agent/coordinator.go index 5acafb993d2d40860ae1ccf3992dea9c3e1b7980..16ceb21a38669af83261a212b861193ae2e89779 100644 --- a/internal/agent/coordinator.go +++ b/internal/agent/coordinator.go @@ -508,7 +508,7 @@ func (c *coordinator) buildAgentModels(ctx context.Context, isSubAgent bool) (Mo return Model{}, Model{}, errors.New("large model provider not configured") } - smallProvider, err := c.buildProvider(smallProviderCfg, largeModelCfg, true) + smallProvider, err := c.buildProvider(smallProviderCfg, smallModelCfg, true) if err != nil { return Model{}, Model{}, err } From 54d924b0a8d8c09717d893e3230dc8913d56b01f Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Fri, 20 Feb 2026 15:03:14 -0300 Subject: [PATCH 31/50] fix: more reliably detect windows drive (#2273) --- internal/agent/tools/bash.go | 9 ++------- internal/fsext/drive_other.go | 16 ++++++++++++++++ internal/fsext/drive_windows.go | 26 ++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 internal/fsext/drive_other.go create mode 100644 internal/fsext/drive_windows.go diff --git a/internal/agent/tools/bash.go b/internal/agent/tools/bash.go index ca3612e091f23235688a2a40006469e39093d6a5..8552880b99b7735172ed89c9b6be147c104dcb5d 100644 --- a/internal/agent/tools/bash.go +++ b/internal/agent/tools/bash.go @@ -7,7 +7,6 @@ import ( _ "embed" "fmt" "html/template" - "os" "path/filepath" "runtime" "strings" @@ -15,6 +14,7 @@ import ( "charm.land/fantasy" "github.com/charmbracelet/crush/internal/config" + "github.com/charmbracelet/crush/internal/fsext" "github.com/charmbracelet/crush/internal/permission" "github.com/charmbracelet/crush/internal/shell" ) @@ -431,12 +431,7 @@ func countLines(s string) int { func normalizeWorkingDir(path string) string { if runtime.GOOS == "windows" { - cwd, err := os.Getwd() - if err != nil { - cwd = "C:" - } - path = strings.ReplaceAll(path, filepath.VolumeName(cwd), "") + path = strings.ReplaceAll(path, fsext.WindowsWorkingDirDrive(), "") } - return filepath.ToSlash(path) } diff --git a/internal/fsext/drive_other.go b/internal/fsext/drive_other.go new file mode 100644 index 0000000000000000000000000000000000000000..0141c8baf0a640a6c3fc45500c9acb798664b16a --- /dev/null +++ b/internal/fsext/drive_other.go @@ -0,0 +1,16 @@ +//go:build !windows + +package fsext + +// WindowsWorkingDirDrive returns the drive letter of the current working +// directory, e.g. "C:". +// Falls back to the system drive if the current working directory cannot be +// determined. +func WindowsWorkingDirDrive() string { + panic("cannot call fsext.WindowsWorkingDirDrive() on non-Windows OS") +} + +// WindowsSystemDrive returns the drive letter of the system drive, e.g. "C:". +func WindowsSystemDrive() string { + panic("cannot call fsext.WindowsSystemDrive() on non-Windows OS") +} diff --git a/internal/fsext/drive_windows.go b/internal/fsext/drive_windows.go new file mode 100644 index 0000000000000000000000000000000000000000..7d0a798da27fb59d38bce5e5bec52560ff18b54b --- /dev/null +++ b/internal/fsext/drive_windows.go @@ -0,0 +1,26 @@ +//go:build windows + +package fsext + +import ( + "cmp" + "os" + "path/filepath" +) + +// WindowsWorkingDirDrive returns the drive letter of the current working +// directory, e.g. "C:". +// Falls back to the system drive if the current working directory cannot be +// determined. +func WindowsWorkingDirDrive() string { + if cwd, err := os.Getwd(); err == nil { + return filepath.VolumeName(cwd) + } + return WindowsSystemDrive() +} + +// WindowsSystemDrive returns the drive letter of the system drive, e.g. "C:". +func WindowsSystemDrive() string { + systemRoot := cmp.Or(os.Getenv("SYSTEMROOT"), os.Getenv("WINDIR")) + return filepath.VolumeName(systemRoot) +} From c9074a017796a2072a5b1703a725ff87a27be17b Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Fri, 20 Feb 2026 15:18:57 -0300 Subject: [PATCH 33/50] ci: fix release action, update go to 1.26 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8c58e6bdf7bd1492665daf7b9ac966edec0da0d5..0cc6e465c675c03cb6d005fd2df5e4fca6bdeadd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: goreleaser: uses: charmbracelet/meta/.github/workflows/goreleaser.yml@main with: - go_version: "1.25" + go_version: "1.26" macos_sign_entitlements: "./.github/entitlements.plist" # XXX: remove it after goreleaser 2.14. goreleaser_version: nightly From 3f07c90efe618e4889d09d8e2effe4d75867c4ce Mon Sep 17 00:00:00 2001 From: Charm <124303983+charmcli@users.noreply.github.com> Date: Fri, 20 Feb 2026 20:36:07 -0300 Subject: [PATCH 35/50] chore(legal): @erikstmartin has signed the CLA --- .github/cla-signatures.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/cla-signatures.json b/.github/cla-signatures.json index 018f4fd81763b24f05111de5e8c1273d1ff89f22..6ee42e1c61aef1ad45ca42b673a68b708ce51651 100644 --- a/.github/cla-signatures.json +++ b/.github/cla-signatures.json @@ -1271,6 +1271,14 @@ "created_at": "2026-02-18T10:37:53Z", "repoId": 987670088, "pullRequestNo": 2246 + }, + { + "name": "erikstmartin", + "id": 50041, + "comment_id": 3937646631, + "created_at": "2026-02-20T23:35:55Z", + "repoId": 987670088, + "pullRequestNo": 2274 } ] } \ No newline at end of file From 12a6372bee85e72b717aa407747395258ad40ee7 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Sat, 21 Feb 2026 16:03:58 +0300 Subject: [PATCH 36/50] fix(ui): apply the message style to each line of the message items Related: 46ebd20b63d8 --- internal/ui/chat/messages.go | 7 ++++++- internal/ui/chat/tools.go | 19 +++++++++++-------- internal/ui/chat/user.go | 12 +++++++++--- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/internal/ui/chat/messages.go b/internal/ui/chat/messages.go index 5dac49c08d32ae2315f9d8096f0410b2511ecb04..8b14e91ad76e866662d2def273fb5cffd3328f95 100644 --- a/internal/ui/chat/messages.go +++ b/internal/ui/chat/messages.go @@ -221,7 +221,12 @@ func (a *AssistantInfoItem) RawRender(width int) string { // Render implements MessageItem. func (a *AssistantInfoItem) Render(width int) string { - return a.sty.Chat.Message.SectionHeader.Render(a.RawRender(width)) + prefix := a.sty.Chat.Message.SectionHeader.Render() + lines := strings.Split(a.RawRender(width), "\n") + for i, line := range lines { + lines[i] = prefix + line + } + return strings.Join(lines, "\n") } func (a *AssistantInfoItem) renderContent(width int) string { diff --git a/internal/ui/chat/tools.go b/internal/ui/chat/tools.go index f7702cc1fe516bb3dee7d57ce15fed050299019f..619aad5a04e59aa66fb9d190fa25686db07484f9 100644 --- a/internal/ui/chat/tools.go +++ b/internal/ui/chat/tools.go @@ -321,16 +321,19 @@ func (t *baseToolMessageItem) RawRender(width int) string { // Render renders the tool message item at the given width. func (t *baseToolMessageItem) Render(width int) string { - style := t.sty.Chat.Message.ToolCallBlurred - if t.focused { - style = t.sty.Chat.Message.ToolCallFocused - } - + var prefix string if t.isCompact { - style = t.sty.Chat.Message.ToolCallCompact + prefix = t.sty.Chat.Message.ToolCallCompact.Render() + } else if t.focused { + prefix = t.sty.Chat.Message.ToolCallFocused.Render() + } else { + prefix = t.sty.Chat.Message.ToolCallBlurred.Render() } - - return style.Render(t.RawRender(width)) + lines := strings.Split(t.RawRender(width), "\n") + for i, ln := range lines { + lines[i] = prefix + ln + } + return strings.Join(lines, "\n") } // ToolCall returns the tool call associated with this message item. diff --git a/internal/ui/chat/user.go b/internal/ui/chat/user.go index 91211590ce66dd0dd7edbde03becdf469e26b521..a2ccf9d476e686818b284a074f462a9f65012edc 100644 --- a/internal/ui/chat/user.go +++ b/internal/ui/chat/user.go @@ -70,11 +70,17 @@ func (m *UserMessageItem) RawRender(width int) string { // Render implements MessageItem. func (m *UserMessageItem) Render(width int) string { - style := m.sty.Chat.Message.UserBlurred + var prefix string if m.focused { - style = m.sty.Chat.Message.UserFocused + prefix = m.sty.Chat.Message.UserFocused.Render() + } else { + prefix = m.sty.Chat.Message.UserBlurred.Render() + } + lines := strings.Split(m.RawRender(width), "\n") + for i, line := range lines { + lines[i] = prefix + line } - return style.Render(m.RawRender(width)) + return strings.Join(lines, "\n") } // ID implements MessageItem. From e3376ad117f8cfd267fa8a94221662b45e58d44a Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Sat, 21 Feb 2026 14:01:21 -0500 Subject: [PATCH 37/50] fix(ui): fix cases where compact header and footer bleed off screen (#2279) --- internal/ui/model/header.go | 18 ++++++++++-------- internal/ui/model/status.go | 4 +++- internal/ui/model/ui.go | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/internal/ui/model/header.go b/internal/ui/model/header.go index 92321d5d9cf67c96731fab102436f662f86cdc1b..24254a0f69e5803e4bcbe89274f21db5b04ef541 100644 --- a/internal/ui/model/header.go +++ b/internal/ui/model/header.go @@ -17,10 +17,11 @@ import ( ) const ( - headerDiag = "╱" - minHeaderDiags = 3 - leftPadding = 1 - rightPadding = 1 + headerDiag = "╱" + minHeaderDiags = 3 + leftPadding = 1 + rightPadding = 1 + diagToDetailsSpacing = 1 // space between diagonal pattern and details section ) type header struct { @@ -73,7 +74,7 @@ func (h *header) drawHeader( var b strings.Builder b.WriteString(h.compactLogo) - availDetailWidth := width - leftPadding - rightPadding - lipgloss.Width(b.String()) - minHeaderDiags + availDetailWidth := width - leftPadding - rightPadding - lipgloss.Width(b.String()) - minHeaderDiags - diagToDetailsSpacing details := renderHeaderDetails( h.com, session, @@ -86,7 +87,8 @@ func (h *header) drawHeader( lipgloss.Width(b.String()) - lipgloss.Width(details) - leftPadding - - rightPadding + rightPadding - + diagToDetailsSpacing if remainingWidth > 0 { b.WriteString(t.Header.Diagonals.Render( @@ -143,8 +145,8 @@ func renderHeaderDetails( const dirTrimLimit = 4 cfg := com.Config() cwd := fsext.DirTrim(fsext.PrettyPath(cfg.WorkingDir()), dirTrimLimit) - cwd = ansi.Truncate(cwd, max(0, availWidth-lipgloss.Width(metadata)), "…") cwd = t.Header.WorkingDir.Render(cwd) - return cwd + metadata + result := cwd + metadata + return ansi.Truncate(result, max(0, availWidth), "…") } diff --git a/internal/ui/model/status.go b/internal/ui/model/status.go index 66dd4082bcc90470129b4a8ebf4ebd65e8567d6c..00f637832cf67a65efb66630308234f353169d3c 100644 --- a/internal/ui/model/status.go +++ b/internal/ui/model/status.go @@ -46,7 +46,9 @@ func (s *Status) ClearInfoMsg() { // SetWidth sets the width of the status bar and help view. func (s *Status) SetWidth(width int) { - s.help.SetWidth(width) + helpStyle := s.com.Styles.Status.Help + horizontalPadding := helpStyle.GetPaddingLeft() + helpStyle.GetPaddingRight() + s.help.SetWidth(width - horizontalPadding) } // ShowingAll returns whether the full help view is shown. diff --git a/internal/ui/model/ui.go b/internal/ui/model/ui.go index 194fa704991b40170d945106bf502a58b98d5f72..8ee3a36ad680ee12c2087dcc64eda6c3b6675215 100644 --- a/internal/ui/model/ui.go +++ b/internal/ui/model/ui.go @@ -1815,7 +1815,7 @@ func (m *UI) drawHeader(scr uv.Screen, area uv.Rectangle) { m.session, m.isCompact, m.detailsOpen, - m.width, + area.Dx(), ) } From d6312f4f3d2813fc0eac06b00ca3a4932cb5a15d Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Sat, 21 Feb 2026 09:58:01 -0500 Subject: [PATCH 38/50] chore(styles): create specific styles for image loading indicators --- internal/ui/chat/tools.go | 13 +++++++------ internal/ui/styles/styles.go | 12 ++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/internal/ui/chat/tools.go b/internal/ui/chat/tools.go index 619aad5a04e59aa66fb9d190fa25686db07484f9..c0059010cc4efaeb0c883fbf2f050c785f19da2b 100644 --- a/internal/ui/chat/tools.go +++ b/internal/ui/chat/tools.go @@ -623,12 +623,13 @@ func toolOutputImageContent(sty *styles.Styles, data, mediaType string) string { dataSize := len(data) * 3 / 4 sizeStr := formatSize(dataSize) - loaded := sty.Base.Foreground(sty.Green).Render("Loaded") - arrow := sty.Base.Foreground(sty.GreenDark).Render("→") - typeStyled := sty.Base.Render(mediaType) - sizeStyled := sty.Subtle.Render(sizeStr) - - return sty.Tool.Body.Render(fmt.Sprintf("%s %s %s %s", loaded, arrow, typeStyled, sizeStyled)) + return sty.Tool.Body.Render(fmt.Sprintf( + "%s %s %s %s", + sty.Tool.ResourceLoadedText.String(), + sty.Tool.ResourceLoadedIndicator.String(), + sty.Base.Render(mediaType), + sty.Subtle.Render(sizeStr), + )) } // getDigits returns the number of digits in a number. diff --git a/internal/ui/styles/styles.go b/internal/ui/styles/styles.go index c0a15bc69ebd103adaa3d193645915184b64361a..c2c54156c6facc9fb5ccb32281a1631994e62bad 100644 --- a/internal/ui/styles/styles.go +++ b/internal/ui/styles/styles.go @@ -321,6 +321,12 @@ type Styles struct { MCPName lipgloss.Style // The mcp name MCPToolName lipgloss.Style // The mcp tool name MCPArrow lipgloss.Style // The mcp arrow icon + + // Images and external resources + ResourceLoadedText lipgloss.Style + ResourceLoadedIndicator lipgloss.Style + ResourceSize lipgloss.Style + MediaType lipgloss.Style } // Dialog styles @@ -1168,6 +1174,12 @@ func DefaultStyles() Styles { s.Tool.MCPToolName = base.Foreground(blueDark) s.Tool.MCPArrow = base.Foreground(blue).SetString(ArrowRightIcon) + // Loading indicators for images, skills + s.Tool.ResourceLoadedText = base.Foreground(green).SetString("Loaded") + s.Tool.ResourceLoadedIndicator = base.Foreground(greenDark).SetString(ArrowRightIcon) + s.Tool.MediaType = base + s.Tool.ResourceSize = base.Foreground(fgMuted) + // Buttons s.ButtonFocus = lipgloss.NewStyle().Foreground(white).Background(secondary) s.ButtonBlur = s.Base.Background(bgSubtle) From c1d294d161dbee0d1bd5061c3270050c980b8d98 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Sat, 21 Feb 2026 10:23:30 -0500 Subject: [PATCH 39/50] feat(ui): indicate when skills are loaded --- internal/agent/tools/view.go | 33 +++++++++++++++++++++++++++------ internal/ui/chat/file.go | 6 ++++++ internal/ui/chat/tools.go | 19 +++++++++++++++---- internal/ui/styles/styles.go | 6 ++++-- 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/internal/agent/tools/view.go b/internal/agent/tools/view.go index 0a754dcb4fd05cc975f84e85532eeab1525c7002..5d589f74012f91f0401573c2017722a9d48b7677 100644 --- a/internal/agent/tools/view.go +++ b/internal/agent/tools/view.go @@ -17,6 +17,7 @@ import ( "github.com/charmbracelet/crush/internal/filetracker" "github.com/charmbracelet/crush/internal/lsp" "github.com/charmbracelet/crush/internal/permission" + "github.com/charmbracelet/crush/internal/skills" ) //go:embed view.md @@ -34,9 +35,19 @@ type ViewPermissionsParams struct { Limit int `json:"limit"` } +type ViewResourceType string + +const ( + ViewResourceUnset ViewResourceType = "" + ViewResourceSkill ViewResourceType = "skill" +) + type ViewResponseMetadata struct { - FilePath string `json:"file_path"` - Content string `json:"content"` + FilePath string `json:"file_path"` + Content string `json:"content"` + ResourceType ViewResourceType `json:"resource_type,omitempty"` + ResourceName string `json:"resource_name,omitempty"` + ResourceDescription string `json:"resource_description,omitempty"` } const ( @@ -196,12 +207,22 @@ func NewViewTool( output += "\n\n" output += getDiagnostics(filePath, lspManager) filetracker.RecordRead(ctx, sessionID, filePath) + + meta := ViewResponseMetadata{ + FilePath: filePath, + Content: content, + } + if isSkillFile { + if skill, err := skills.Parse(filePath); err == nil { + meta.ResourceType = ViewResourceSkill + meta.ResourceName = skill.Name + meta.ResourceDescription = skill.Description + } + } + return fantasy.WithResponseMetadata( fantasy.NewTextResponse(output), - ViewResponseMetadata{ - FilePath: filePath, - Content: content, - }, + meta, ), nil }) } diff --git a/internal/ui/chat/file.go b/internal/ui/chat/file.go index d558f79d597871bf6074d33c76b44549ee6725d5..3b1fef8530506be70e512a3cb801ed34a81e0c62 100644 --- a/internal/ui/chat/file.go +++ b/internal/ui/chat/file.go @@ -82,6 +82,12 @@ func (v *ViewToolRenderContext) RenderTool(sty *styles.Styles, width int, opts * content = meta.Content } + // Handle skill content. + if meta.ResourceType == tools.ViewResourceSkill { + body := toolOutputSkillContent(sty, meta.ResourceName, meta.ResourceDescription) + return joinToolParts(header, body) + } + if content == "" { return header } diff --git a/internal/ui/chat/tools.go b/internal/ui/chat/tools.go index c0059010cc4efaeb0c883fbf2f050c785f19da2b..17c15911e377318d4c4a1515fca57332f31996e1 100644 --- a/internal/ui/chat/tools.go +++ b/internal/ui/chat/tools.go @@ -625,10 +625,21 @@ func toolOutputImageContent(sty *styles.Styles, data, mediaType string) string { return sty.Tool.Body.Render(fmt.Sprintf( "%s %s %s %s", - sty.Tool.ResourceLoadedText.String(), - sty.Tool.ResourceLoadedIndicator.String(), - sty.Base.Render(mediaType), - sty.Subtle.Render(sizeStr), + sty.Tool.ResourceLoadedText.Render("Loaded Image"), + sty.Tool.ResourceLoadedIndicator.Render(styles.ArrowRightIcon), + sty.Tool.MediaType.Render(mediaType), + sty.Tool.ResourceSize.Render(sizeStr), + )) +} + +// toolOutputSkillContent renders a skill loaded indicator. +func toolOutputSkillContent(sty *styles.Styles, name, description string) string { + return sty.Tool.Body.Render(fmt.Sprintf( + "%s %s %s %s", + sty.Tool.ResourceLoadedText.Render("Loaded Skill"), + sty.Tool.ResourceLoadedIndicator.Render(styles.ArrowRightIcon), + sty.Tool.ResourceName.Render(name), + sty.Tool.ResourceSize.Render(description), )) } diff --git a/internal/ui/styles/styles.go b/internal/ui/styles/styles.go index c2c54156c6facc9fb5ccb32281a1631994e62bad..0870f62674f8241cd874d61532f18c3bc58dc22f 100644 --- a/internal/ui/styles/styles.go +++ b/internal/ui/styles/styles.go @@ -325,6 +325,7 @@ type Styles struct { // Images and external resources ResourceLoadedText lipgloss.Style ResourceLoadedIndicator lipgloss.Style + ResourceName lipgloss.Style ResourceSize lipgloss.Style MediaType lipgloss.Style } @@ -1175,8 +1176,9 @@ func DefaultStyles() Styles { s.Tool.MCPArrow = base.Foreground(blue).SetString(ArrowRightIcon) // Loading indicators for images, skills - s.Tool.ResourceLoadedText = base.Foreground(green).SetString("Loaded") - s.Tool.ResourceLoadedIndicator = base.Foreground(greenDark).SetString(ArrowRightIcon) + s.Tool.ResourceLoadedText = base.Foreground(green) + s.Tool.ResourceLoadedIndicator = base.Foreground(greenDark) + s.Tool.ResourceName = base s.Tool.MediaType = base s.Tool.ResourceSize = base.Foreground(fgMuted) From 6e019e9a40d78ada51c9bbfdbd9fb6b7aa1aa960 Mon Sep 17 00:00:00 2001 From: Charm <124303983+charmcli@users.noreply.github.com> Date: Mon, 23 Feb 2026 10:13:03 -0300 Subject: [PATCH 41/50] chore(legal): @Jaylonnet has signed the CLA --- .github/cla-signatures.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/cla-signatures.json b/.github/cla-signatures.json index 6ee42e1c61aef1ad45ca42b673a68b708ce51651..4026b8c990a227a4a99f6193ff798f4f383e5f09 100644 --- a/.github/cla-signatures.json +++ b/.github/cla-signatures.json @@ -1279,6 +1279,14 @@ "created_at": "2026-02-20T23:35:55Z", "repoId": 987670088, "pullRequestNo": 2274 + }, + { + "name": "Jaylonnet", + "id": 101283545, + "comment_id": 3944717192, + "created_at": "2026-02-23T13:12:50Z", + "repoId": 987670088, + "pullRequestNo": 2293 } ] } \ No newline at end of file From 262c74ef8c0bd5528be3562657ed1641d50b8f90 Mon Sep 17 00:00:00 2001 From: huaiyuWangh <34158348+huaiyuWangh@users.noreply.github.com> Date: Tue, 24 Feb 2026 04:19:55 +0800 Subject: [PATCH 42/50] fix(agent): fix minor bugs in coordinator and view tool (#2276) - Fix misleading error message: report "small model provider not configured" instead of "large" when the small model provider is missing - Fix error handling order in view tool: check readTextFile error before UTF-8 validation to avoid validating partial/empty content - Fix MCP tool filtering: move "MCP not allowed" log into correct branch and break after tool is added to prevent duplicate additions --- internal/agent/coordinator.go | 5 +++-- internal/agent/tools/view.go | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/internal/agent/coordinator.go b/internal/agent/coordinator.go index 16ceb21a38669af83261a212b861193ae2e89779..27d2f7163b3607245b88c8ca32a142cee42e93e9 100644 --- a/internal/agent/coordinator.go +++ b/internal/agent/coordinator.go @@ -472,9 +472,10 @@ func (c *coordinator) buildTools(ctx context.Context, agent config.Agent) ([]fan } if len(tools) == 0 || slices.Contains(tools, tool.MCPToolName()) { filteredTools = append(filteredTools, tool) + break } + slog.Debug("MCP not allowed", "tool", tool.Name(), "agent", agent.Name) } - slog.Debug("MCP not allowed", "tool", tool.Name(), "agent", agent.Name) } slices.SortFunc(filteredTools, func(a, b fantasy.AgentTool) int { return strings.Compare(a.Info().Name, b.Info().Name) @@ -505,7 +506,7 @@ func (c *coordinator) buildAgentModels(ctx context.Context, isSubAgent bool) (Mo smallProviderCfg, ok := c.cfg.Providers.Get(smallModelCfg.Provider) if !ok { - return Model{}, Model{}, errors.New("large model provider not configured") + return Model{}, Model{}, errors.New("small model provider not configured") } smallProvider, err := c.buildProvider(smallProviderCfg, smallModelCfg, true) diff --git a/internal/agent/tools/view.go b/internal/agent/tools/view.go index 5d589f74012f91f0401573c2017722a9d48b7677..0e56a4f6866d018efabfa952b7a10dc97507656f 100644 --- a/internal/agent/tools/view.go +++ b/internal/agent/tools/view.go @@ -186,13 +186,13 @@ func NewViewTool( // Read the file content content, lineCount, err := readTextFile(filePath, params.Offset, params.Limit) + if err != nil { + return fantasy.ToolResponse{}, fmt.Errorf("error reading file: %w", err) + } isValidUt8 := utf8.ValidString(content) if !isValidUt8 { return fantasy.NewTextErrorResponse("File content is not valid UTF-8"), nil } - if err != nil { - return fantasy.ToolResponse{}, fmt.Errorf("error reading file: %w", err) - } notifyLSPs(ctx, lspManager, filePath) output := "\n" From eb12fbef1f489755ce9d452acdd904839b5f6081 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Mon, 23 Feb 2026 17:28:49 -0300 Subject: [PATCH 43/50] chore: update `x/powernap` (#2295) * Closes https://github.com/charmbracelet/crush/discussions/2287 * Ref https://github.com/charmbracelet/x/pull/784 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 52ba10616772c6f0c18e47944a9c384e156ec90d..14cc0fc16ee5769ce05e72bdb8e6119ca480871d 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/charmbracelet/x/exp/ordered v0.1.0 github.com/charmbracelet/x/exp/slice v0.0.0-20260209194814-eeb2896ac759 github.com/charmbracelet/x/exp/strings v0.1.0 - github.com/charmbracelet/x/powernap v0.0.0-20260209132835-6b065b8ba62c + github.com/charmbracelet/x/powernap v0.1.0 github.com/charmbracelet/x/term v0.2.2 github.com/clipperhouse/displaywidth v0.10.0 github.com/clipperhouse/uax29/v2 v2.7.0 diff --git a/go.sum b/go.sum index 76611757eb1d223ee711b4b5b8b0953d12050868..526f8bdf0a63de863850e0d91f4ee112e78c112e 100644 --- a/go.sum +++ b/go.sum @@ -120,8 +120,8 @@ github.com/charmbracelet/x/exp/strings v0.1.0 h1:i69S2XI7uG1u4NLGeJPSYU++Nmjvpo9 github.com/charmbracelet/x/exp/strings v0.1.0/go.mod h1:/ehtMPNh9K4odGFkqYJKpIYyePhdp1hLBRvyY4bWkH8= github.com/charmbracelet/x/json v0.2.0 h1:DqB+ZGx2h+Z+1s98HOuOyli+i97wsFQIxP2ZQANTPrQ= github.com/charmbracelet/x/json v0.2.0/go.mod h1:opFIflx2YgXgi49xVUu8gEQ21teFAxyMwvOiZhIvWNM= -github.com/charmbracelet/x/powernap v0.0.0-20260209132835-6b065b8ba62c h1:6E+Y7WQ6Rnw+FmeXoRBtyCBkPcXS0hSMuws6QBr+nyQ= -github.com/charmbracelet/x/powernap v0.0.0-20260209132835-6b065b8ba62c/go.mod h1:cmdl5zlP5mR8TF2Y68UKc7hdGUDiSJ2+4hk0h04Hsx4= +github.com/charmbracelet/x/powernap v0.1.0 h1:xJPM8szKu3UY4ZuW3puc8R7Hpftq2nLIygyRe3EGUoE= +github.com/charmbracelet/x/powernap v0.1.0/go.mod h1:cmdl5zlP5mR8TF2Y68UKc7hdGUDiSJ2+4hk0h04Hsx4= github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI= github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY= From 0ac3d9afe2abe91ff7b2f4f1f1424e5fce03745e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 17:41:07 -0300 Subject: [PATCH 44/50] chore(deps): bump goreleaser/goreleaser-action in the all group (#2289) Bumps the all group with 1 update: [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action). Updates `goreleaser/goreleaser-action` from 6.4.0 to 7.0.0 - [Release notes](https://github.com/goreleaser/goreleaser-action/releases) - [Commits](https://github.com/goreleaser/goreleaser-action/compare/e435ccd777264be153ace6237001ef4d979d3a7a...ec59f474b9834571250b370d4735c50f8e2d1e29) --- updated-dependencies: - dependency-name: goreleaser/goreleaser-action dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: all ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/snapshot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index a5a45d8fdeeaf8f0c1374366e7c1d34839c1acc5..3c139d5b7664315e7b66271df5ec0fa2fb52ca4f 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 with: go-version-file: go.mod - - uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0 + - uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0 with: version: "nightly" distribution: goreleaser-pro From 38c6632b2ddefad3060dd4ec920d7bf1c18d944b Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Mon, 23 Feb 2026 17:42:39 -0300 Subject: [PATCH 45/50] fix: wrap correct error (#2296) Fixes #2284 --- internal/config/provider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/config/provider.go b/internal/config/provider.go index bd960e0c27ca11d5ef376c221717f061ad3deb47..645f863628edb8335782fa6c4424ee36f1b10f0e 100644 --- a/internal/config/provider.go +++ b/internal/config/provider.go @@ -162,7 +162,7 @@ func Providers(cfg *Config) ([]catwalk.Provider, error) { items, err := catwalkSyncer.Get(ctx) if err != nil { catwalkURL := fmt.Sprintf("%s/v2/providers", cmp.Or(os.Getenv("CATWALK_URL"), defaultCatwalkURL)) - errs = append(errs, fmt.Errorf("Crush was unable to fetch an updated list of providers from %s. Consider setting CRUSH_DISABLE_PROVIDER_AUTO_UPDATE=1 to use the embedded providers bundled at the time of this Crush release. You can also update providers manually. For more info see crush update-providers --help.\n\nCause: %w", catwalkURL, providerErr)) //nolint:staticcheck + errs = append(errs, fmt.Errorf("Crush was unable to fetch an updated list of providers from %s. Consider setting CRUSH_DISABLE_PROVIDER_AUTO_UPDATE=1 to use the embedded providers bundled at the time of this Crush release. You can also update providers manually. For more info see crush update-providers --help.\n\nCause: %w", catwalkURL, err)) //nolint:staticcheck return } providers.Append(items...) From c65b807bbdf25b51f6d0de4922c1efeb8bd96872 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Mon, 23 Feb 2026 17:55:23 -0300 Subject: [PATCH 46/50] ci: allow `MIT-0` dependencies (#2297) One of our indirect dependencies switched to "MIT-0". This is even more permissive than MIT, so totally valid for us. * https://github.com/segmentio/asm/pull/86 Check failure: * https://github.com/charmbracelet/crush/pull/2290 * https://github.com/charmbracelet/crush/actions/runs/22323633569/job/64588201366?pr=2290 About the license: * https://github.com/aws/mit-0 * https://opensource.org/license/mit-0 --- .github/workflows/security.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 0ec626008218192017791edf82972bcae57b0a5f..3d488dfaf901404d00a29a6aa52a32ba01f360e3 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -89,4 +89,4 @@ jobs: - uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4.8.3 with: fail-on-severity: critical - allow-licenses: BSD-2-Clause, BSD-3-Clause, MIT, Apache-2.0, MPL-2.0, ISC, LicenseRef-scancode-google-patent-license-golang, Unlicense + allow-licenses: BSD-2-Clause, BSD-3-Clause, MIT, MIT-0, Apache-2.0, MPL-2.0, ISC, LicenseRef-scancode-google-patent-license-golang, Unlicense From 57a09a1b4251c99685b6145b4701d1e9037223e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 21:03:52 +0000 Subject: [PATCH 47/50] chore(deps): bump the all group with 3 updates (#2290) Bumps the all group with 3 updates: [charm.land/catwalk](https://github.com/charmbracelet/catwalk), [github.com/clipperhouse/displaywidth](https://github.com/clipperhouse/displaywidth) and [github.com/pressly/goose/v3](https://github.com/pressly/goose). Updates `charm.land/catwalk` from 0.21.0 to 0.21.1 - [Release notes](https://github.com/charmbracelet/catwalk/releases) - [Commits](https://github.com/charmbracelet/catwalk/compare/v0.21.0...v0.21.1) Updates `github.com/clipperhouse/displaywidth` from 0.10.0 to 0.11.0 - [Release notes](https://github.com/clipperhouse/displaywidth/releases) - [Changelog](https://github.com/clipperhouse/displaywidth/blob/main/CHANGELOG.md) - [Commits](https://github.com/clipperhouse/displaywidth/compare/v0.10.0...v0.11.0) Updates `github.com/pressly/goose/v3` from 3.26.0 to 3.27.0 - [Release notes](https://github.com/pressly/goose/releases) - [Changelog](https://github.com/pressly/goose/blob/main/CHANGELOG.md) - [Commits](https://github.com/pressly/goose/compare/v3.26.0...v3.27.0) --- updated-dependencies: - dependency-name: charm.land/catwalk dependency-version: 0.21.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all - dependency-name: github.com/clipperhouse/displaywidth dependency-version: 0.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all - dependency-name: github.com/pressly/goose/v3 dependency-version: 3.27.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 16 ++++++++-------- go.sum | 40 ++++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 14cc0fc16ee5769ce05e72bdb8e6119ca480871d..ad06663ada838d46d9c8c0fa64d50c2f6b417c90 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.26.0 require ( charm.land/bubbles/v2 v2.0.0-rc.1.0.20260109112849-ae99f46cec66 charm.land/bubbletea/v2 v2.0.0-rc.2.0.20260209074636-30878e43d7b0 - charm.land/catwalk v0.21.0 + charm.land/catwalk v0.21.1 charm.land/fantasy v0.9.0 charm.land/glamour/v2 v2.0.0-20260123212943-6014aa153a9b charm.land/lipgloss/v2 v2.0.0-beta.3.0.20260212100304-e18737634dea @@ -33,7 +33,7 @@ require ( github.com/charmbracelet/x/exp/strings v0.1.0 github.com/charmbracelet/x/powernap v0.1.0 github.com/charmbracelet/x/term v0.2.2 - github.com/clipperhouse/displaywidth v0.10.0 + github.com/clipperhouse/displaywidth v0.11.0 github.com/clipperhouse/uax29/v2 v2.7.0 github.com/denisbrodbeck/machineid v1.0.1 github.com/disintegration/imaging v1.6.2 @@ -51,7 +51,7 @@ require ( github.com/openai/openai-go/v2 v2.7.1 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/posthog/posthog-go v1.10.0 - github.com/pressly/goose/v3 v3.26.0 + github.com/pressly/goose/v3 v3.27.0 github.com/qjebbs/go-jsons v1.0.0-alpha.4 github.com/rivo/uniseg v0.4.7 github.com/sahilm/fuzzy v0.1.1 @@ -148,10 +148,10 @@ require ( github.com/muesli/roff v0.1.0 // indirect github.com/ncruces/go-strftime v1.0.0 // indirect github.com/ncruces/julianday v1.0.0 // indirect - github.com/pierrec/lz4/v4 v4.1.22 // indirect + github.com/pierrec/lz4/v4 v4.1.25 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/segmentio/asm v1.2.0 // indirect + github.com/segmentio/asm v1.2.1 // indirect github.com/segmentio/encoding v0.5.3 // indirect github.com/sethvargo/go-retry v0.3.0 // indirect github.com/spf13/pflag v1.0.9 // indirect @@ -174,7 +174,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v4 v4.0.0-rc.3 // indirect golang.org/x/crypto v0.48.0 // indirect - golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a // indirect + golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect golang.org/x/image v0.36.0 // indirect golang.org/x/oauth2 v0.35.0 // indirect golang.org/x/sys v0.41.0 // indirect @@ -182,13 +182,13 @@ require ( golang.org/x/time v0.14.0 // indirect google.golang.org/api v0.266.0 // indirect google.golang.org/genai v1.47.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d // indirect google.golang.org/grpc v1.79.1 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/dnaeon/go-vcr.v4 v4.0.6-0.20251110073552-01de4eb40290 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - modernc.org/libc v1.67.6 // indirect + modernc.org/libc v1.68.0 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect ) diff --git a/go.sum b/go.sum index 526f8bdf0a63de863850e0d91f4ee112e78c112e..1b6418c22177adeb1ae34dfb34d1f0fb4ad52788 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ charm.land/bubbles/v2 v2.0.0-rc.1.0.20260109112849-ae99f46cec66 h1:2BdJynsAW+8rv charm.land/bubbles/v2 v2.0.0-rc.1.0.20260109112849-ae99f46cec66/go.mod h1:5AbN6cEd/47gkEf8TgiQ2O3RZ5QxMS14l9W+7F9fPC4= charm.land/bubbletea/v2 v2.0.0-rc.2.0.20260209074636-30878e43d7b0 h1:HAbpM9TPjZM18D677ww3VnkKXdd2hyMQtHUsVV0HcPQ= charm.land/bubbletea/v2 v2.0.0-rc.2.0.20260209074636-30878e43d7b0/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ= -charm.land/catwalk v0.21.0 h1:ShexIXWiyFH9QOV9EqQikUUdrvidiFm8PYXGl9Ql6VA= -charm.land/catwalk v0.21.0/go.mod h1:rFC/V96rIHX7VES215c/qzI1EW/Moo1ggs1Q6seTy5s= +charm.land/catwalk v0.21.1 h1:CO6GDgfl6u0Gx6v3vC64B8DEnX+PhjDxX7IrVyu3Feg= +charm.land/catwalk v0.21.1/go.mod h1:rFC/V96rIHX7VES215c/qzI1EW/Moo1ggs1Q6seTy5s= charm.land/fantasy v0.9.0 h1:2KzDYZC3IDb6T8KhWn4akqDHoU5Evr+VwL2xbaWtXmM= charm.land/fantasy v0.9.0/go.mod h1:vpR/vcgCtKZ5SWHNbW/5c1b+DMDNNO15j+t/evoQb/4= charm.land/glamour/v2 v2.0.0-20260123212943-6014aa153a9b h1:A6IUUyChZDWP16RUdRJCfmYISAKWQGyIcfhZJUCViQ0= @@ -128,8 +128,8 @@ github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8 github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo= github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM= github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k= -github.com/clipperhouse/displaywidth v0.10.0 h1:GhBG8WuerxjFQQYeuZAeVTuyxuX+UraiZGD4HJQ3Y8g= -github.com/clipperhouse/displaywidth v0.10.0/go.mod h1:XqJajYsaiEwkxOj4bowCTMcT1SgvHo9flfF3jQasdbs= +github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= +github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik= @@ -286,8 +286,8 @@ github.com/openai/openai-go/v2 v2.7.1 h1:/tfvTJhfv7hTSL8mWwc5VL4WLLSDL5yn9VqVykd github.com/openai/openai-go/v2 v2.7.1/go.mod h1:jrJs23apqJKKbT+pqtFgNKpRju/KP9zpUTZhz3GElQE= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= -github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= -github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.25 h1:kocOqRffaIbU5djlIBr7Wh+cx82C0vtFb0fOurZHqD0= +github.com/pierrec/lz4/v4 v4.1.25/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -300,8 +300,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posthog/posthog-go v1.10.0 h1:wfoy7Jfb4LigCoHYyMZoiJmmEoCLOkSaYfDxM/NtCqY= github.com/posthog/posthog-go v1.10.0/go.mod h1:wB3/9Q7d9gGb1P/yf/Wri9VBlbP8oA8z++prRzL5OcY= -github.com/pressly/goose/v3 v3.26.0 h1:KJakav68jdH0WDvoAcj8+n61WqOIaPGgH0bJWS6jpmM= -github.com/pressly/goose/v3 v3.26.0/go.mod h1:4hC1KrritdCxtuFsqgs1R4AU5bWtTAf+cnWvfhf2DNY= +github.com/pressly/goose/v3 v3.27.0 h1:/D30gVTuQhu0WsNZYbJi4DMOsx1lNq+6SkLe+Wp59BM= +github.com/pressly/goose/v3 v3.27.0/go.mod h1:3ZBeCXqzkgIRvrEMDkYh1guvtoJTU5oMMuDdkutoM78= github.com/qjebbs/go-jsons v1.0.0-alpha.4 h1:Qsb4ohRUHQODIUAsJKdKJ/SIDbsO7oGOzsfy+h1yQZs= github.com/qjebbs/go-jsons v1.0.0-alpha.4/go.mod h1:wNJrtinHyC3YSf6giEh4FJN8+yZV7nXBjvmfjhBIcw4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= @@ -315,8 +315,8 @@ github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y= github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= -github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= -github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= +github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w= github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -400,8 +400,8 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o= -golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= +golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= +golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc= golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4= @@ -495,8 +495,8 @@ google.golang.org/api v0.266.0 h1:hco+oNCf9y7DmLeAtHJi/uBAY7n/7XC9mZPxu1ROiyk= google.golang.org/api v0.266.0/go.mod h1:Jzc0+ZfLnyvXma3UtaTl023TdhZu6OMBP9tJ+0EmFD0= google.golang.org/genai v1.47.0 h1:iWCS7gEdO6rctOqfCYLOrZGKu2D+N42aTnCEcBvB1jo= google.golang.org/genai v1.47.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d h1:t/LOSXPJ9R0B6fnZNyALBRfZBH0Uy0gT+uR+SJ6syqQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY= google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= @@ -520,18 +520,18 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= -modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc= -modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM= +modernc.org/ccgo/v4 v4.30.2 h1:4yPaaq9dXYXZ2V8s1UgrC3KIj580l2N4ClrLwnbv2so= +modernc.org/ccgo/v4 v4.30.2/go.mod h1:yZMnhWEdW0qw3EtCndG1+ldRrVGS+bIwyWmAWzS0XEw= modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= -modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE= -modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= +modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= -modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI= -modernc.org/libc v1.67.6/go.mod h1:JAhxUVlolfYDErnwiqaLvUqc8nfb2r6S6slAgZOnaiE= +modernc.org/libc v1.68.0 h1:PJ5ikFOV5pwpW+VqCK1hKJuEWsonkIJhhIXyuF/91pQ= +modernc.org/libc v1.68.0/go.mod h1:NnKCYeoYgsEqnY3PgvNgAeaJnso968ygU8Z0DxjoEc0= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= From dcc67b784556c01570fd7cb73020dc7fbd7a884e Mon Sep 17 00:00:00 2001 From: huaiyuWangh <34158348+huaiyuWangh@users.noreply.github.com> Date: Wed, 25 Feb 2026 01:02:57 +0800 Subject: [PATCH 48/50] fix(app): fix goroutine leak, shutdown context, and model matching (#2298) - Add missing return after error send in RunNonInteractive goroutine - Use context.WithoutCancel for shutdown to preserve tracing context - Use strings.EqualFold for case-insensitive model matching - Preserve LSP ConnectedAt across state transitions --- internal/app/app.go | 3 ++- internal/app/lsp_events.go | 2 ++ internal/app/provider.go | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/internal/app/app.go b/internal/app/app.go index e923a0337f125cab17192e94ef61e17d23ae6582..3755db0d5321029b88cc1c15d8fb99911f635bf3 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -246,6 +246,7 @@ func (app *App) RunNonInteractive(ctx context.Context, output io.Writer, prompt, done <- response{ err: fmt.Errorf("failed to start agent processing stream: %w", err), } + return } done <- response{ result: result, @@ -551,7 +552,7 @@ func (app *App) Shutdown() { var wg sync.WaitGroup // Shared shutdown context for all timeout-bounded cleanup. - shutdownCtx, cancel := context.WithTimeout(app.globalCtx, 5*time.Second) + shutdownCtx, cancel := context.WithTimeout(context.WithoutCancel(app.globalCtx), 5*time.Second) defer cancel() // Send exit event diff --git a/internal/app/lsp_events.go b/internal/app/lsp_events.go index 5292983d46cf867b9380ad45f7831007da54f0d7..babb9afe374108e1b80c4fb8910032f0c631f302 100644 --- a/internal/app/lsp_events.go +++ b/internal/app/lsp_events.go @@ -67,6 +67,8 @@ func updateLSPState(name string, state lsp.ServerState, err error, client *lsp.C } if state == lsp.StateReady { info.ConnectedAt = time.Now() + } else if existing, ok := lspStates.Get(name); ok { + info.ConnectedAt = existing.ConnectedAt } lspStates.Set(name, info) diff --git a/internal/app/provider.go b/internal/app/provider.go index 570edadf9e1647eeeeab32107d3da3a1d3494935..ea7c6ee110a74c17f80a667e7b891317437f6963 100644 --- a/internal/app/provider.go +++ b/internal/app/provider.go @@ -70,8 +70,8 @@ func findModels(providers map[string]config.ProviderConfig, largeModel, smallMod } func filter(modelFilter, providerFilter, model, provider string) bool { - return modelFilter != "" && model == modelFilter && - (providerFilter == "" || provider == providerFilter) + return modelFilter != "" && strings.EqualFold(model, modelFilter) && + (providerFilter == "" || strings.EqualFold(provider, providerFilter)) } // Validate and return a single match. From c0462191b33bc25af6e096092cf57e812d2be129 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Tue, 24 Feb 2026 14:05:37 -0300 Subject: [PATCH 49/50] chore: update lip gloss, bubble tea and bubbles to v2.0.0 (#2299) --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index ad06663ada838d46d9c8c0fa64d50c2f6b417c90..c47e9b613eac3b7e1fdce1063b8ce623d2fb2c35 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,12 @@ module github.com/charmbracelet/crush go 1.26.0 require ( - charm.land/bubbles/v2 v2.0.0-rc.1.0.20260109112849-ae99f46cec66 - charm.land/bubbletea/v2 v2.0.0-rc.2.0.20260209074636-30878e43d7b0 + charm.land/bubbles/v2 v2.0.0 + charm.land/bubbletea/v2 v2.0.0 charm.land/catwalk v0.21.1 charm.land/fantasy v0.9.0 charm.land/glamour/v2 v2.0.0-20260123212943-6014aa153a9b - charm.land/lipgloss/v2 v2.0.0-beta.3.0.20260212100304-e18737634dea + charm.land/lipgloss/v2 v2.0.0 charm.land/log/v2 v2.0.0-20251110204020-529bb77f35da charm.land/x/vcr v0.1.1 github.com/JohannesKaufmann/html-to-markdown v1.6.0 @@ -137,7 +137,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-runewidth v0.0.19 // indirect + github.com/mattn/go-runewidth v0.0.20 // indirect github.com/mfridman/interpolate v0.0.2 // indirect github.com/microcosm-cc/bluemonday v1.0.27 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect diff --git a/go.sum b/go.sum index 1b6418c22177adeb1ae34dfb34d1f0fb4ad52788..685c4df3f6ed6efcab0002e61088fa7ecb37c49b 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,15 @@ -charm.land/bubbles/v2 v2.0.0-rc.1.0.20260109112849-ae99f46cec66 h1:2BdJynsAW+8rv9xq6ZS+x0mtacfxpxjIK1KUIeTqBOs= -charm.land/bubbles/v2 v2.0.0-rc.1.0.20260109112849-ae99f46cec66/go.mod h1:5AbN6cEd/47gkEf8TgiQ2O3RZ5QxMS14l9W+7F9fPC4= -charm.land/bubbletea/v2 v2.0.0-rc.2.0.20260209074636-30878e43d7b0 h1:HAbpM9TPjZM18D677ww3VnkKXdd2hyMQtHUsVV0HcPQ= -charm.land/bubbletea/v2 v2.0.0-rc.2.0.20260209074636-30878e43d7b0/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ= +charm.land/bubbles/v2 v2.0.0 h1:tE3eK/pHjmtrDiRdoC9uGNLgpopOd8fjhEe31B/ai5s= +charm.land/bubbles/v2 v2.0.0/go.mod h1:rCHoleP2XhU8um45NTuOWBPNVHxnkXKTiZqcclL/qOI= +charm.land/bubbletea/v2 v2.0.0 h1:p0d6CtWyJXJ9GfzMpUUqbP/XUUhhlk06+vCKWmox1wQ= +charm.land/bubbletea/v2 v2.0.0/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ= charm.land/catwalk v0.21.1 h1:CO6GDgfl6u0Gx6v3vC64B8DEnX+PhjDxX7IrVyu3Feg= charm.land/catwalk v0.21.1/go.mod h1:rFC/V96rIHX7VES215c/qzI1EW/Moo1ggs1Q6seTy5s= charm.land/fantasy v0.9.0 h1:2KzDYZC3IDb6T8KhWn4akqDHoU5Evr+VwL2xbaWtXmM= charm.land/fantasy v0.9.0/go.mod h1:vpR/vcgCtKZ5SWHNbW/5c1b+DMDNNO15j+t/evoQb/4= charm.land/glamour/v2 v2.0.0-20260123212943-6014aa153a9b h1:A6IUUyChZDWP16RUdRJCfmYISAKWQGyIcfhZJUCViQ0= charm.land/glamour/v2 v2.0.0-20260123212943-6014aa153a9b/go.mod h1:J3kVhY6oHXZq5f+8vC3hmDO95fEvbqj3z7xDwxrfzU8= -charm.land/lipgloss/v2 v2.0.0-beta.3.0.20260212100304-e18737634dea h1:XBmpGhIKPN8o9VjuXg+X5WXFsEqUs/YtPx0Q0zzmTTA= -charm.land/lipgloss/v2 v2.0.0-beta.3.0.20260212100304-e18737634dea/go.mod h1:xylWHUuJWcFJqoGrKdZP8Z0y3THC6xqrnfl1IYDviTE= +charm.land/lipgloss/v2 v2.0.0 h1:sd8N/B3x892oiOjFfBQdXBQp3cAkvjGaU5TvVZC3ivo= +charm.land/lipgloss/v2 v2.0.0/go.mod h1:w6SnmsBFBmEFBodiEDurGS/sdUY/u1+v72DqUzc6J14= charm.land/log/v2 v2.0.0-20251110204020-529bb77f35da h1:vZa/Ow0uLclpfaDY0ubjzE+B0eLQqi2zanmpeALanow= charm.land/log/v2 v2.0.0-20251110204020-529bb77f35da/go.mod h1:Tj12StbPc4GwksDF6XwhC9wdXouinIVxRGKKmmmzdSU= charm.land/x/vcr v0.1.1 h1:PXCFMUG0rPtyk35rhfzYCJEduOzWXCIbrXTFq4OF/9Q= @@ -254,8 +254,8 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= -github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ= +github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= From dff955fcdb3e613eeb35e75c433a54891e5fe6e7 Mon Sep 17 00:00:00 2001 From: 0xarcher Date: Wed, 25 Feb 2026 01:09:13 +0800 Subject: [PATCH 50/50] fix(mcp): gracefully handle Method not found for resources/list (#2239) Some MCP servers advertise resources capability but don't implement resources/list, causing the entire MCP client to fail. This change handles JSON-RPC error code -32601 gracefully by marking resources as unavailable instead of failing. Fixes #2227 --- internal/agent/tools/mcp/resources.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/internal/agent/tools/mcp/resources.go b/internal/agent/tools/mcp/resources.go index 912651f0eb4d5c8cf3999cc1fb7f6027cd9bcd52..da661817c24f8fc1324f509d1834e9d03d5fd2c9 100644 --- a/internal/agent/tools/mcp/resources.go +++ b/internal/agent/tools/mcp/resources.go @@ -2,11 +2,13 @@ package mcp import ( "context" + "errors" "iter" "log/slog" "github.com/charmbracelet/crush/internal/config" "github.com/charmbracelet/crush/internal/csync" + "github.com/modelcontextprotocol/go-sdk/jsonrpc" "github.com/modelcontextprotocol/go-sdk/mcp" ) @@ -81,11 +83,22 @@ func getResources(ctx context.Context, c *ClientSession) ([]*Resource, error) { } result, err := c.ListResources(ctx, &mcp.ListResourcesParams{}) if err != nil { + // Handle "Method not found" errors from MCP servers that don't support resources/list + if isMethodNotFoundError(err) { + slog.Warn("MCP server does not support resources/list", "error", err) + return nil, nil + } return nil, err } return result.Resources, nil } +// isMethodNotFoundError checks if the error is a JSON-RPC "Method not found" error. +func isMethodNotFoundError(err error) bool { + var rpcErr *jsonrpc.Error + return errors.As(err, &rpcErr) && rpcErr != nil && rpcErr.Code == jsonrpc.CodeMethodNotFound +} + func updateResources(name string, resources []*Resource) int { if len(resources) == 0 { allResources.Del(name)