using System.IO; using ClaudeDo.Data; using ClaudeDo.Installer.Core; namespace ClaudeDo.Installer.Checks; /// Without write access nothing can be installed — blocking. public sealed class WriteAccessCheck : IEnvironmentCheck { public const string CheckId = "write-access"; public string Id => CheckId; public CheckSeverity Severity => CheckSeverity.Error; public Task RunAsync(InstallContext ctx, CancellationToken ct) { foreach (var target in new[] { ctx.InstallDirectory, Paths.AppDataRoot() }) { var error = TryWrite(target); if (error is not null) { return Task.FromResult(CheckResult.Fail(Id, Severity, "checks.writeAccess.title", $"Cannot write to '{target}': {error}", "checks.writeAccess.hint")); } } return Task.FromResult(CheckResult.Ok(Id, Severity, "checks.writeAccess.title", "Install directory and data directory are writable.")); } private static string? TryWrite(string path) { var probeDir = FirstExistingParent(path); var probeFile = Path.Combine(probeDir, $".claudedo-write-check-{Guid.NewGuid():N}.tmp"); try { File.WriteAllText(probeFile, string.Empty); return null; } catch (Exception ex) { return ex.Message; } finally { try { File.Delete(probeFile); } catch { /* best-effort cleanup */ } } } private static string FirstExistingParent(string path) { var current = Path.GetFullPath(path); while (!Directory.Exists(current)) { var parent = Path.GetDirectoryName(current); if (string.IsNullOrEmpty(parent) || parent == current) break; current = parent; } return current; } }