summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-09-26 07:52:08 +0300
committerPaul Buetow <paul@buetow.org>2025-09-26 07:52:08 +0300
commit2efcd2c4dda97831058851e8911281d5db5ce1c6 (patch)
treec59059cb4c781878f1291ca06fe1a215579a0fa8 /internal
parentd0330d02ff040326216ab940a767490cb2de09ce (diff)
Log config reload changes
Diffstat (limited to 'internal')
-rw-r--r--internal/lsp/chat_commands.go14
-rw-r--r--internal/lsp/chat_commands_test.go2
-rw-r--r--internal/runtimeconfig/store.go19
-rw-r--r--internal/runtimeconfig/store_test.go37
4 files changed, 57 insertions, 15 deletions
diff --git a/internal/lsp/chat_commands.go b/internal/lsp/chat_commands.go
index 31347e9..89efa49 100644
--- a/internal/lsp/chat_commands.go
+++ b/internal/lsp/chat_commands.go
@@ -45,19 +45,7 @@ func (s *Server) handleReloadCommand() chatCommandResult {
s.logger.Printf("config reload failed: %v", err)
return chatCommandResult{message: fmt.Sprintf("Reload failed: %v", err)}
}
- summary := formatReloadSummary(changes)
+ summary := runtimeconfig.FormatSummary("Reloaded config", changes)
s.logger.Print(summary)
return chatCommandResult{message: summary}
}
-
-func formatReloadSummary(changes []runtimeconfig.Change) string {
- if len(changes) == 0 {
- return "Reloaded config (no changes detected)."
- }
- lines := make([]string, 0, len(changes)+1)
- lines = append(lines, fmt.Sprintf("Reloaded config (%d changes):", len(changes)))
- for _, ch := range changes {
- lines = append(lines, fmt.Sprintf("- %s: %s → %s", ch.Key, ch.Old, ch.New))
- }
- return strings.Join(lines, "\n")
-}
diff --git a/internal/lsp/chat_commands_test.go b/internal/lsp/chat_commands_test.go
index f9bd6a0..87cc1b4 100644
--- a/internal/lsp/chat_commands_test.go
+++ b/internal/lsp/chat_commands_test.go
@@ -17,7 +17,7 @@ func TestFormatReloadSummary(t *testing.T) {
{Key: "max_tokens", Old: "200", New: "128"},
{Key: "provider", Old: "openai", New: "ollama"},
}
- got := formatReloadSummary(changes)
+ got := runtimeconfig.FormatSummary("Reloaded config", changes)
if !strings.Contains(got, "Reloaded config (2 changes):") {
t.Fatalf("expected change count line, got %q", got)
}
diff --git a/internal/runtimeconfig/store.go b/internal/runtimeconfig/store.go
index e0a594c..3112951 100644
--- a/internal/runtimeconfig/store.go
+++ b/internal/runtimeconfig/store.go
@@ -85,7 +85,11 @@ func (s *Store) Reload(logger *log.Logger, opts appconfig.LoadOptions) ([]Change
if err := cfg.Validate(); err != nil {
return nil, err
}
- return s.Set(cfg), nil
+ changes := s.Set(cfg)
+ if logger != nil {
+ logger.Print(FormatSummary("Reloaded config", changes))
+ }
+ return changes, nil
}
// Diff computes a stable, sorted list of key/value changes between two configuration snapshots.
@@ -176,3 +180,16 @@ func stringifyValue(v reflect.Value) string {
return fmt.Sprint(v.Interface())
}
}
+
+// FormatSummary creates a human-readable summary for configuration changes.
+func FormatSummary(prefix string, changes []Change) string {
+ if len(changes) == 0 {
+ return fmt.Sprintf("%s (no changes detected).", prefix)
+ }
+ lines := make([]string, 0, len(changes)+1)
+ lines = append(lines, fmt.Sprintf("%s (%d changes):", prefix, len(changes)))
+ for _, ch := range changes {
+ lines = append(lines, fmt.Sprintf("- %s: %s → %s", ch.Key, ch.Old, ch.New))
+ }
+ return strings.Join(lines, "\n")
+}
diff --git a/internal/runtimeconfig/store_test.go b/internal/runtimeconfig/store_test.go
index 9973a1a..6e40c76 100644
--- a/internal/runtimeconfig/store_test.go
+++ b/internal/runtimeconfig/store_test.go
@@ -1,10 +1,12 @@
package runtimeconfig
import (
+ "bytes"
"io"
"log"
"os"
"path/filepath"
+ "strings"
"testing"
"codeberg.org/snonux/hexai/internal/appconfig"
@@ -57,3 +59,38 @@ func TestStoreReloadSkipsEnvOverrides(t *testing.T) {
t.Fatalf("expected max_tokens change in diff, got %#v", changes)
}
}
+
+func TestStoreReloadLogsSummary(t *testing.T) {
+ var buf bytes.Buffer
+ logger := log.New(&buf, "", 0)
+ tmp := t.TempDir()
+ configDir := filepath.Join(tmp, "hexai")
+ if err := os.MkdirAll(configDir, 0o755); err != nil {
+ t.Fatalf("mkdir: %v", err)
+ }
+ configPath := filepath.Join(configDir, "config.toml")
+ if err := os.WriteFile(configPath, []byte("[general]\nmax_tokens = 64\n"), 0o644); err != nil {
+ t.Fatalf("write config: %v", err)
+ }
+
+ t.Setenv("XDG_CONFIG_HOME", tmp)
+ t.Setenv("HEXAI_MAX_TOKENS", "321")
+
+ initial := appconfig.Load(logger)
+ store := New(initial)
+ if err := os.WriteFile(configPath, []byte("[general]\nmax_tokens = 128\n"), 0o644); err != nil {
+ t.Fatalf("update config: %v", err)
+ }
+
+ _, err := store.Reload(logger, appconfig.LoadOptions{IgnoreEnv: true})
+ if err != nil {
+ t.Fatalf("reload failed: %v", err)
+ }
+ logOutput := buf.String()
+ if !strings.Contains(logOutput, "Reloaded config (1 changes):") {
+ t.Fatalf("expected summary line in log, got %q", logOutput)
+ }
+ if !strings.Contains(logOutput, "- max_tokens: 321 → 128") {
+ t.Fatalf("expected change details in log, got %q", logOutput)
+ }
+}