diff --git a/src/Directory.props b/src/Directory.props
index 0f6e534..b04a64d 100644
--- a/src/Directory.props
+++ b/src/Directory.props
@@ -11,6 +11,8 @@
https://clarius.blob.core.windows.net/nuget/index.json
+
+ bcfa6afd-d165-4505-b752-f00318604d0c
\ No newline at end of file
diff --git a/src/OpenLaw/App.cs b/src/OpenLaw/App.cs
index add2115..fa29e15 100644
--- a/src/OpenLaw/App.cs
+++ b/src/OpenLaw/App.cs
@@ -3,6 +3,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http.Resilience;
using Spectre.Console;
@@ -17,6 +18,15 @@ public static CommandApp Create(out IServiceProvider services)
{
var collection = new ServiceCollection();
+ var config = new ConfigurationBuilder()
+ .AddEnvironmentVariables()
+ .AddUserSecrets()
+ .AddDotNetConfig()
+ .Build();
+
+ collection.AddSingleton(config)
+ .AddSingleton(_ => config);
+
collection.AddHttpClient()
.ConfigureHttpClientDefaults(defaults => defaults.ConfigureHttpClient(http =>
{
@@ -58,12 +68,14 @@ public static CommandApp Create(out IServiceProvider services)
app.Configure(config =>
{
- // configure commands
config.AddBranch("saij", saij =>
{
saij.AddCommand("download");
});
+ config.AddCommand("convert");
+ config.AddCommand("format");
+
if (Environment.GetEnvironmentVariables().Contains("NO_COLOR"))
config.Settings.HelpProviderStyles = null;
});
diff --git a/src/OpenLaw/AssistantOptions.cs b/src/OpenLaw/AssistantOptions.cs
new file mode 100644
index 0000000..ae90af1
--- /dev/null
+++ b/src/OpenLaw/AssistantOptions.cs
@@ -0,0 +1,21 @@
+namespace Clarius.OpenLaw;
+
+public class AssistantOptions
+{
+ ///
+ /// The assistant id.
+ ///
+ public required string Id { get; set; }
+ ///
+ /// The assistant access key/token.
+ ///
+ public required string Key { get; set; }
+ ///
+ /// The assistant endpoint uri.
+ ///
+ public required string Uri { get; set; }
+ ///
+ /// The assistant vector store identifier.
+ ///
+ public required string Store { get; set; }
+}
diff --git a/src/OpenLaw/ConvertCommand.cs b/src/OpenLaw/ConvertCommand.cs
new file mode 100644
index 0000000..d115614
--- /dev/null
+++ b/src/OpenLaw/ConvertCommand.cs
@@ -0,0 +1,63 @@
+using System.ComponentModel;
+using System.Text.Json;
+using Spectre.Console;
+using Spectre.Console.Cli;
+using YamlDotNet.Serialization;
+
+namespace Clarius.OpenLaw;
+
+[Description("Convierte archivos JSON a YAML y Markdown.")]
+public class ConvertCommand(IAnsiConsole console) : Command
+{
+ public override int Execute(CommandContext context, ConvertSettings settings)
+ {
+ if (settings.File is not null)
+ {
+ ConvertFile(settings.File, true);
+ return 0;
+ }
+
+ if (Directory.Exists(settings.Directory))
+ {
+ console.Progress()
+ .Columns(
+ [
+ new TaskDescriptionColumn(),
+ new ProgressBarColumn(),
+ ])
+ .Start(ctx =>
+ {
+ Parallel.ForEach(Directory.EnumerateFiles(settings.Directory, "*.json", SearchOption.AllDirectories), file =>
+ {
+ var task = ctx.AddTask($"Convirtiendo {file}");
+ task.IsIndeterminate = true;
+ ConvertFile(file, true);
+ task.Value(100);
+ });
+ });
+ }
+
+ return 0;
+ }
+
+ static void ConvertFile(string file, bool overwrite) => DictionaryConverter.ConvertFile(file, overwrite);
+
+ public class ConvertSettings : CommandSettings
+ {
+ public override ValidationResult Validate()
+ {
+ if (!string.IsNullOrWhiteSpace(File) && !System.IO.File.Exists(File))
+ return ValidationResult.Error("El archivo especificado '{File}' no existe.");
+
+ return base.Validate();
+ }
+
+ [Description("Archivo a convertir. Opcional.")]
+ [CommandArgument(0, "[file]")]
+ public string? File { get; set; }
+
+ [Description("Ubicación de archivos a convertir. Por defecto '%AppData%\\clarius\\openlaw'")]
+ [CommandOption("--dir")]
+ public string Directory { get; set; } = Environment.ExpandEnvironmentVariables("%AppData%\\clarius\\openlaw");
+ }
+}
diff --git a/src/OpenLaw/DictionaryConverter.cs b/src/OpenLaw/DictionaryConverter.cs
new file mode 100644
index 0000000..a497bf6
--- /dev/null
+++ b/src/OpenLaw/DictionaryConverter.cs
@@ -0,0 +1,117 @@
+using System.Text;
+using System.Text.Json;
+using YamlDotNet.Serialization;
+
+namespace Clarius.OpenLaw;
+
+public class DictionaryConverter
+{
+ static readonly JsonSerializerOptions options = new()
+ {
+ Converters = { new JsonDictionaryConverter() },
+ };
+
+ public static void ConvertFile(string jsonFile, bool overwrite)
+ {
+ var yamlDir = Path.Combine(Path.GetDirectoryName(jsonFile) ?? "", "yaml");
+ var yamlFile = Path.Combine(yamlDir, Path.ChangeExtension(Path.GetFileName(jsonFile), ".yaml"));
+ Directory.CreateDirectory(yamlDir);
+
+ var mdDir = Path.Combine(Path.GetDirectoryName(jsonFile) ?? "", "md");
+ var mdFile = Path.Combine(mdDir, Path.ChangeExtension(Path.GetFileName(jsonFile), ".md"));
+ Directory.CreateDirectory(mdDir);
+
+ Dictionary? dictionary = null;
+
+ if (overwrite || !File.Exists(yamlFile))
+ {
+ dictionary = Parse(File.ReadAllText(jsonFile));
+ if (dictionary is null)
+ return;
+
+ File.WriteAllText(yamlFile, ToYaml(dictionary), Encoding.UTF8);
+ }
+
+ if (overwrite || !File.Exists(mdFile))
+ {
+ if (dictionary is null)
+ dictionary = Parse(File.ReadAllText(jsonFile));
+ if (dictionary is null)
+ return;
+
+ File.WriteAllText(mdFile, ToMarkdown(dictionary), Encoding.UTF8);
+ }
+ }
+
+ public static Dictionary? Parse(string json)
+ => JsonSerializer.Deserialize>(json, options);
+
+ public static string ToYaml(Dictionary dictionary)
+ {
+ var serializer = new SerializerBuilder()
+ .WithTypeConverter(new YamlDictionaryConverter())
+ .WithTypeConverter(new YamlListConverter())
+ .Build();
+
+ return serializer.Serialize(dictionary);
+ }
+
+ public static string ToMarkdown(Dictionary dictionary)
+ {
+ var output = new StringBuilder();
+ ProcessDictionary(0, dictionary!, output);
+ return output.ToString();
+ }
+
+ static void ProcessObject(int depth, object? obj, StringBuilder output)
+ {
+ if (obj is Dictionary dictionary)
+ {
+ ProcessDictionary(depth, dictionary, output);
+ }
+ else if (obj is List