diff --git a/src/ClaudeMailbox/Config/ConfigResolver.cs b/src/ClaudeMailbox/Config/ConfigResolver.cs new file mode 100644 index 0000000..7fec2db --- /dev/null +++ b/src/ClaudeMailbox/Config/ConfigResolver.cs @@ -0,0 +1,30 @@ +using ClaudeMailbox.Cli; + +namespace ClaudeMailbox.Config; + +public static class ConfigResolver +{ + public static DaemonConfig Build(string[] serveArgs, FileConfig file) + { + var cliPort = ParseIntOption(serveArgs, "--port"); + var cliBind = ClientCommands.GetOption(serveArgs, "--bind"); + var cliDbPath = ClientCommands.GetOption(serveArgs, "--db-path"); + + var port = cliPort ?? file.Port ?? DaemonConfig.DefaultPort; + var bind = cliBind ?? file.Bind ?? DaemonConfig.DefaultBindAddress; + var dbPathRaw = cliDbPath ?? file.DbPath ?? Paths.DefaultDbPath(); + + return new DaemonConfig + { + Port = port, + BindAddress = bind, + DbPath = Paths.Expand(dbPathRaw), + }; + } + + private static int? ParseIntOption(string[] args, string name) + { + var raw = ClientCommands.GetOption(args, name); + return int.TryParse(raw, out var v) ? v : null; + } +} diff --git a/tests/ClaudeMailbox.Tests/Config/ConfigResolverTests.cs b/tests/ClaudeMailbox.Tests/Config/ConfigResolverTests.cs new file mode 100644 index 0000000..69ee9a0 --- /dev/null +++ b/tests/ClaudeMailbox.Tests/Config/ConfigResolverTests.cs @@ -0,0 +1,59 @@ +using ClaudeMailbox.Config; + +namespace ClaudeMailbox.Tests.Config; + +public sealed class ConfigResolverTests +{ + [Fact] + public void CliFlag_WinsOverFile() + { + var file = new FileConfig { Port = 1000 }; + var cfg = ConfigResolver.Build(new[] { "--port", "9999" }, file); + Assert.Equal(9999, cfg.Port); + } + + [Fact] + public void File_WinsOverDefault() + { + var file = new FileConfig { Port = 1000, Bind = "0.0.0.0", DbPath = "/tmp/x.db" }; + var cfg = ConfigResolver.Build(Array.Empty(), file); + Assert.Equal(1000, cfg.Port); + Assert.Equal("0.0.0.0", cfg.BindAddress); + Assert.Equal(Paths.Expand("/tmp/x.db"), cfg.DbPath); + } + + [Fact] + public void Default_UsedWhenNeitherCliNorFile() + { + var cfg = ConfigResolver.Build(Array.Empty(), new FileConfig()); + Assert.Equal(DaemonConfig.DefaultPort, cfg.Port); + Assert.Equal(DaemonConfig.DefaultBindAddress, cfg.BindAddress); + Assert.Equal(Paths.DefaultDbPath(), cfg.DbPath); + } + + [Fact] + public void Mixed_CliPort_FileDbPath_DefaultBind() + { + var file = new FileConfig { DbPath = "/tmp/mixed.db" }; + var cfg = ConfigResolver.Build(new[] { "--port", "7000" }, file); + Assert.Equal(7000, cfg.Port); + Assert.Equal(DaemonConfig.DefaultBindAddress, cfg.BindAddress); + Assert.Equal(Paths.Expand("/tmp/mixed.db"), cfg.DbPath); + } + + [Fact] + public void CliDbPath_ExpandsEnvVars() + { + var file = new FileConfig(); + var cfg = ConfigResolver.Build(new[] { "--db-path", "~/foo.db" }, file); + Assert.DoesNotContain("~", cfg.DbPath); + } + + [Fact] + public void InvalidPortFlag_FallsBackToFileOrDefault() + { + var file = new FileConfig { Port = 4242 }; + var cfg = ConfigResolver.Build(new[] { "--port", "not-a-number" }, file); + Assert.Equal(4242, cfg.Port); + } +}