Editor/Drivers/ProjectSettingsDriver.cs

Editor-side static driver for managing simple project settings files. It lists available .config files, reads a config into a string, and writes/upserts keys into a JSON config file under ProjectSettings in the project root.

File Access
#nullable enable
using System;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using Sandbox;

namespace Editor.Mcp
{
	internal static class ProjectSettingsDriver
	{
		public static ToolOutcome<object> ManageSettings( string action, string? configName = null, string? key = null, string? value = null )
		{
			var project = Project.Current;
			if ( project == null )
			{
				return ToolOutcome<object>.Failure( null, ToolStatus.Unavailable, "settings.no_project", "No active project loaded." );
			}

			var normAction = action.ToLowerInvariant().Trim();
			var settingsDir = Path.Combine( project.GetRootPath(), "ProjectSettings" );
			Directory.CreateDirectory( settingsDir );

			if ( normAction == "list_configs" )
			{
				var files = Directory.Exists( settingsDir ) ? Directory.GetFiles( settingsDir, "*.config" ).Select( Path.GetFileName ).ToArray() : Array.Empty<string>();
				return ToolOutcome<object>.Ready( new
				{
					Project = project.Config.Ident,
					Type = project.Config.Type,
					AvailableConfigs = files
				} );
			}

			var targetConfig = configName ?? "Platform";
			var configPath = Path.Combine( settingsDir, $"{targetConfig}.config" );

			if ( normAction == "read" )
			{
				var content = File.Exists( configPath ) ? File.ReadAllText( configPath ) : "{}";
				return ToolOutcome<object>.Ready( new
				{
					ConfigName = targetConfig,
					Content = content,
					Exists = File.Exists( configPath )
				} );
			}

			if ( normAction == "write" && !string.IsNullOrWhiteSpace( key ) && value != null )
			{
				JsonObject configObj;
				try
				{
					var existing = File.Exists( configPath ) ? File.ReadAllText( configPath ) : "{}";
					configObj = JsonNode.Parse( existing ) as JsonObject ?? new JsonObject();
				}
				catch
				{
					configObj = new JsonObject();
				}

				// Parse value into strongly-typed json node if possible
				JsonNode? nodeValue;
				if ( bool.TryParse( value, out var b ) )
				{
					nodeValue = JsonValue.Create( b );
				}
				else if ( int.TryParse( value, out var i ) )
				{
					nodeValue = JsonValue.Create( i );
				}
				else if ( float.TryParse( value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out var f ) )
				{
					nodeValue = JsonValue.Create( f );
				}
				else
				{
					try
					{
						nodeValue = JsonNode.Parse( value ) ?? JsonValue.Create( value );
					}
					catch
					{
						nodeValue = JsonValue.Create( value );
					}
				}

				configObj[key] = nodeValue;
				var options = new JsonSerializerOptions { WriteIndented = true };
				File.WriteAllText( configPath, configObj.ToJsonString( options ) );

				return ToolOutcome<object>.Ready( new
				{
					ConfigName = targetConfig,
					UpdatedKey = key,
					UpdatedValue = value,
					Saved = true,
					FilePath = configPath
				} );
			}

			return ToolOutcome<object>.Ready( new { ConfigName = targetConfig, Status = "Ready" } );
		}
	}
}