Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 3 additions & 42 deletions src/Main/CLI/Commands/ConfigCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,48 +81,9 @@ public override async Task<int> ExecuteAsync(
}
else
{
// Default: show entire configuration with all nodes
var config = this.Config;
output = new
{
Nodes = config.Nodes.Select(kvp => new NodeDetailsDto
{
NodeId = kvp.Key,
Access = kvp.Value.Access.ToString(),
ContentIndex = new ContentIndexConfigDto
{
Type = kvp.Value.ContentIndex.Type.ToString(),
Path = kvp.Value.ContentIndex is KernelMemory.Core.Config.ContentIndex.SqliteContentIndexConfig sqlite
? sqlite.Path
: null
},
FileStorage = kvp.Value.FileStorage != null ? new StorageConfigDto
{
Type = kvp.Value.FileStorage.Type.ToString()
} : null,
RepoStorage = kvp.Value.RepoStorage != null ? new StorageConfigDto
{
Type = kvp.Value.RepoStorage.Type.ToString()
} : null,
SearchIndexes = kvp.Value.SearchIndexes.Select(si => new SearchIndexDto
{
Type = si.Type.ToString()
}).ToList()
}).ToList(),
Cache = new CacheInfoDto
{
EmbeddingsCache = config.EmbeddingsCache != null ? new CacheConfigDto
{
Type = config.EmbeddingsCache.Type.ToString(),
Path = config.EmbeddingsCache.Path
} : null,
LlmCache = config.LLMCache != null ? new CacheConfigDto
{
Type = config.LLMCache.Type.ToString(),
Path = config.LLMCache.Path
} : null
}
};
// Default: show the actual AppConfig structure (not DTOs)
// This allows users to copy/paste the output into their config file
output = this.Config;
}

formatter.Format(output);
Expand Down
64 changes: 63 additions & 1 deletion tests/Main.Tests/Integration/ConfigCommandTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.

using KernelMemory.Core.Config;
using KernelMemory.Core.Config.Cache;
using KernelMemory.Main.CLI.Commands;
using Spectre.Console.Cli;
using Xunit;
Expand Down Expand Up @@ -32,7 +33,9 @@ public ConfigCommandTests()
["personal"] = NodeConfig.CreateDefaultPersonalNode(Path.Combine(this._tempDir, "nodes", "personal")),
["work"] = NodeConfig.CreateDefaultPersonalNode(Path.Combine(this._tempDir, "nodes", "work")),
["shared"] = NodeConfig.CreateDefaultPersonalNode(Path.Combine(this._tempDir, "nodes", "shared"))
}
},
EmbeddingsCache = CacheConfig.CreateDefaultSqliteCache(Path.Combine(this._tempDir, "embeddings-cache.db")),
LLMCache = null
};

var json = System.Text.Json.JsonSerializer.Serialize(config);
Expand Down Expand Up @@ -109,6 +112,65 @@ public void ConfigCommand_WithoutFlags_ShouldShowEntireConfiguration()
}
}

[Fact]
public void ConfigCommand_OutputStructure_ShouldMatchAppConfigFormat()
{
// This test verifies the BUG: km config output should match AppConfig structure
// so users can copy/paste the output back into their config file

// Arrange
var config = ConfigParser.LoadFromFile(this._configPath);

var settings = new ConfigCommandSettings
{
ConfigPath = this._configPath,
Format = "json"
};

var command = new ConfigCommand(config);
var context = new CommandContext(
new[] { "--config", this._configPath },
new EmptyRemainingArguments(),
"config",
null);

// Capture stdout
using var outputCapture = new StringWriter();
var originalOutput = Console.Out;
Console.SetOut(outputCapture);

try
{
// Act
var exitCode = command.ExecuteAsync(context, settings).GetAwaiter().GetResult();

// Assert
Assert.Equal(Constants.ExitCodeSuccess, exitCode);

var output = outputCapture.ToString();
var outputJson = System.Text.Json.JsonDocument.Parse(output);

// BUG: Current output has "nodes" as an array
// EXPECTED: "nodes" should be an object/dictionary (like in config file)
var nodesElement = outputJson.RootElement.GetProperty("nodes");
Assert.Equal(System.Text.Json.JsonValueKind.Object, nodesElement.ValueKind);
// ^ This will FAIL with current code (it's an Array)

// BUG: Current output has "embeddingsCache" nested under "cache"
// EXPECTED: "embeddingsCache" should be at root level (like in config file)
Assert.True(outputJson.RootElement.TryGetProperty("embeddingsCache", out _));
// ^ This will FAIL with current code (no "embeddingsCache" at root)

// Should NOT have a "cache" wrapper
Assert.False(outputJson.RootElement.TryGetProperty("cache", out _));
// ^ This will FAIL with current code (it has "cache" wrapper)
}
finally
{
Console.SetOut(originalOutput);
}
}

[Fact]
public void ConfigCommand_WithShowNodesFlag_ShouldShowAllNodesSummary()
{
Expand Down
Loading