Detailed changes
@@ -94,7 +94,7 @@ func getDiagnostics(filePath string, lsps *csync.Map[string, *lsp.Client]) strin
}
out := output.String()
- slog.Info("Diagnostics", "output", out)
+ slog.Debug("Diagnostics", "output", out)
return out
}
@@ -109,14 +109,26 @@ func GetState(name string) (ClientInfo, bool) {
// Close closes all MCP clients. This should be called during application shutdown.
func Close() error {
var errs []error
+ var wg sync.WaitGroup
for name, session := range sessions.Seq2() {
- if err := session.Close(); err != nil &&
- !errors.Is(err, io.EOF) &&
- !errors.Is(err, context.Canceled) &&
- err.Error() != "signal: killed" {
- errs = append(errs, fmt.Errorf("close mcp: %s: %w", name, err))
- }
+ wg.Go(func() {
+ done := make(chan bool, 1)
+ go func() {
+ if err := session.Close(); err != nil &&
+ !errors.Is(err, io.EOF) &&
+ !errors.Is(err, context.Canceled) &&
+ err.Error() != "signal: killed" {
+ errs = append(errs, fmt.Errorf("close mcp: %s: %w", name, err))
+ }
+ done <- true
+ }()
+ select {
+ case <-done:
+ case <-time.After(time.Millisecond * 250):
+ }
+ })
}
+ wg.Wait()
broker.Shutdown()
return errors.Join(errs...)
}
@@ -279,9 +291,8 @@ func createSession(ctx context.Context, name string, m config.MCPConfig, resolve
})
},
LoggingMessageHandler: func(_ context.Context, req *mcp.LoggingMessageRequest) {
- slog.Info("mcp log", "name", name, "data", req.Params.Data)
+ slog.Info("MCP log", "name", name, "data", req.Params.Data)
},
- KeepAlive: time.Minute * 10,
},
)
@@ -289,14 +300,14 @@ func createSession(ctx context.Context, name string, m config.MCPConfig, resolve
if err != nil {
err = maybeStdioErr(err, transport)
updateState(name, StateError, maybeTimeoutErr(err, timeout), nil, Counts{})
- slog.Error("error starting mcp client", "error", err, "name", name)
+ slog.Error("MCP client failed to initialize", "error", err, "name", name)
cancel()
cancelTimer.Stop()
return nil, err
}
cancelTimer.Stop()
- slog.Info("Initialized mcp client", "name", name)
+ slog.Info("MCP client initialized", "name", name)
return session, nil
}
@@ -370,30 +370,42 @@ func (app *App) Subscribe(program *tea.Program) {
// Shutdown performs a graceful shutdown of the application.
func (app *App) Shutdown() {
+ start := time.Now()
+ defer func() { slog.Info("Shutdown took " + time.Since(start).String()) }()
+ var wg sync.WaitGroup
if app.AgentCoordinator != nil {
- app.AgentCoordinator.CancelAll()
+ wg.Go(func() {
+ app.AgentCoordinator.CancelAll()
+ })
}
// Kill all background shells.
- shell.GetBackgroundShellManager().KillAll()
+ wg.Go(func() {
+ shell.GetBackgroundShellManager().KillAll()
+ })
// Shutdown all LSP clients.
for name, client := range app.LSPClients.Seq2() {
- shutdownCtx, cancel := context.WithTimeout(app.globalCtx, 5*time.Second)
- if err := client.Close(shutdownCtx); err != nil {
- slog.Error("Failed to shutdown LSP client", "name", name, "error", err)
- }
- cancel()
+ wg.Go(func() {
+ shutdownCtx, cancel := context.WithTimeout(app.globalCtx, 5*time.Second)
+ defer cancel()
+ if err := client.Close(shutdownCtx); err != nil {
+ slog.Error("Failed to shutdown LSP client", "name", name, "error", err)
+ }
+ })
}
// Call call cleanup functions.
for _, cleanup := range app.cleanupFuncs {
if cleanup != nil {
- if err := cleanup(); err != nil {
- slog.Error("Failed to cleanup app properly on shutdown", "error", err)
- }
+ wg.Go(func() {
+ if err := cleanup(); err != nil {
+ slog.Error("Failed to cleanup app properly on shutdown", "error", err)
+ }
+ })
}
}
+ wg.Wait()
}
// checkForUpdates checks for available updates.
@@ -23,11 +23,11 @@ func (app *App) initLSPClients(ctx context.Context) {
// createAndStartLSPClient creates a new LSP client, initializes it, and starts its workspace watcher
func (app *App) createAndStartLSPClient(ctx context.Context, name string, config config.LSPConfig) {
- slog.Info("Creating LSP client", "name", name, "command", config.Command, "fileTypes", config.FileTypes, "args", config.Args)
+ slog.Debug("Creating LSP client", "name", name, "command", config.Command, "fileTypes", config.FileTypes, "args", config.Args)
// Check if any root markers exist in the working directory (config now has defaults)
if !lsp.HasRootMarkers(app.config.WorkingDir(), config.RootMarkers) {
- slog.Info("Skipping LSP client - no root markers found", "name", name, "rootMarkers", config.RootMarkers)
+ slog.Debug("Skipping LSP client: no root markers found", "name", name, "rootMarkers", config.RootMarkers)
updateLSPState(name, lsp.StateDisabled, nil, nil, 0)
return
}
@@ -53,7 +53,7 @@ func (app *App) createAndStartLSPClient(ctx context.Context, name string, config
// Initialize LSP client.
_, err = lspClient.Initialize(initCtx, app.config.WorkingDir())
if err != nil {
- slog.Error("Initialize failed", "name", name, "error", err)
+ slog.Error("LSP client initialization failed", "name", name, "error", err)
updateLSPState(name, lsp.StateError, err, lspClient, 0)
lspClient.Close(ctx)
return
@@ -68,7 +68,7 @@ func (app *App) createAndStartLSPClient(ctx context.Context, name string, config
updateLSPState(name, lsp.StateError, err, lspClient, 0)
} else {
// Server reached a ready state scuccessfully.
- slog.Info("LSP server is ready", "name", name)
+ slog.Debug("LSP server is ready", "name", name)
lspClient.SetServerState(lsp.StateReady)
updateLSPState(name, lsp.StateReady, nil, lspClient, 0)
}