144 lines
5.8 KiB
C#

using Sdt.Config;
using Sdt.Tui;
using Spectre.Console;
try
{
// ── Workspace + project discovery ────────────────────────────────────────
var workspaceResult = WorkspaceLoader.FindAndLoad();
var projectResult = ConfigLoader.FindAndLoad();
var cliArgs = Environment.GetCommandLineArgs().Skip(1).ToArray();
var forceInit = cliArgs.Any(a => string.Equals(a, "init", StringComparison.OrdinalIgnoreCase) ||
string.Equals(a, "--init", StringComparison.OrdinalIgnoreCase));
if (forceInit)
{
var scan = ConfigBootstrapper.Scan(Directory.GetCurrentDirectory());
var generated = ConfigBootstrapper.BuildDefaultConfig(scan);
var path = ConfigBootstrapper.WriteDefaultConfig(scan.ProjectRoot, generated, overwrite: false);
AnsiConsole.MarkupLine(Theme.Ok($"Initialized config at {path}"));
projectResult = ConfigLoader.FindAndLoad(scan.ProjectRoot);
}
if (projectResult is null)
{
AnsiConsole.MarkupLine($"[bold {Theme.Red}]SDT:[/] [{Theme.Amber}]No devtool.json found[/] in current directory or any parent.");
var bootstrap = AnsiConsole.Confirm(
$"[{Theme.Amber}]Generate a default devtool.json for this project now?[/]",
defaultValue: true);
if (!bootstrap)
{
AnsiConsole.MarkupLine(Theme.Faint("Create a devtool.json in your project root to get started."));
return 1;
}
var scan = ConfigBootstrapper.Scan(Directory.GetCurrentDirectory());
AnsiConsole.MarkupLine(Theme.Faint($"Detected project root: {scan.ProjectRoot}"));
if (scan.ToolFamilies.Count > 0)
AnsiConsole.MarkupLine(Theme.Faint($"Detected tool families: {string.Join(", ", scan.ToolFamilies)}"));
var generated = ConfigBootstrapper.BuildDefaultConfig(scan);
var preview = ConfigBootstrapper.ToJson(generated);
AnsiConsole.Write(new Panel(Markup.Escape(preview)).Header("Generated devtool.json preview").BorderStyle(Theme.DimStyle));
var confirmWrite = AnsiConsole.Confirm(
$"[{Theme.Amber}]Write generated devtool.json to {scan.ProjectRoot}?[/]",
defaultValue: true);
if (!confirmWrite)
return 1;
var path = ConfigBootstrapper.WriteDefaultConfig(scan.ProjectRoot, generated, overwrite: false);
AnsiConsole.MarkupLine(Theme.Ok($"Created {path}"));
projectResult = ConfigLoader.FindAndLoad(scan.ProjectRoot);
if (projectResult is null)
{
AnsiConsole.MarkupLine(Theme.Fail("Generated config could not be reloaded."));
return 1;
}
}
// ── Main run loop (handles workspace project switching) ────────────────
var currentLoaded = projectResult;
var (workspace, workspaceRoot) = workspaceResult.HasValue
? (workspaceResult.Value.Config, workspaceResult.Value.WorkspaceRoot)
: ((WorkspaceConfig?)null, (string?)null);
while (true)
{
var app = new App(currentLoaded.Config, currentLoaded.ProjectRoot, currentLoaded.Warnings, workspace, workspaceRoot);
var result = await app.RunAsync();
if (result.Reason == AppExitReason.Quit)
break;
// User switched projects — reload config from new root
if (result.Reason == AppExitReason.SwitchProject && result.NewProjectRoot is not null)
{
LoadedProjectConfig? loaded;
try
{
loaded = ConfigLoader.FindAndLoad(result.NewProjectRoot);
}
catch (Exception ex)
{
AnsiConsole.MarkupLine(Theme.Fail(ex.Message));
AnsiConsole.MarkupLine(Theme.Faint("Press any key to stay on current project..."));
Console.ReadKey(intercept: true);
continue;
}
if (loaded is null)
{
AnsiConsole.MarkupLine(Theme.Fail($"No devtool.json found at: {result.NewProjectRoot}"));
AnsiConsole.MarkupLine(Theme.Faint("Press any key to stay on current project..."));
Console.ReadKey(intercept: true);
continue; // go back to current app
}
currentLoaded = loaded;
}
}
return 0;
}
catch (Exception ex)
{
var message = ex.Message;
var isExpectedMigrationError =
ex is InvalidOperationException &&
message.Contains("Legacy targets-only config detected", StringComparison.OrdinalIgnoreCase);
AnsiConsole.MarkupLine(Theme.Fail($"Fatal: {message}"));
if (isExpectedMigrationError)
{
var configPath = ConfigLoader.FindConfigPath();
if (!string.IsNullOrWhiteSpace(configPath))
{
var migrate = AnsiConsole.Confirm(
$"[{Theme.Amber}]Apply automatic migration now (creates backup + converts targets -> workflows)?[/]",
defaultValue: true);
if (migrate)
{
var result = ConfigLoader.ApplyLegacyTargetMigration(configPath, createBackup: true);
if (result.Success)
{
AnsiConsole.MarkupLine(Theme.Ok("Migration applied successfully."));
if (!string.IsNullOrWhiteSpace(result.BackupPath))
AnsiConsole.MarkupLine(Theme.Faint($"Backup: {result.BackupPath}"));
AnsiConsole.MarkupLine(Theme.Faint("Run sdt.exe again in strict mode."));
}
else
{
AnsiConsole.MarkupLine(Theme.Fail($"Migration failed: {result.Message}"));
}
}
}
}
if (!isExpectedMigrationError)
AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything);
return 1;
}