feat(worker): session skill registry (install/update/remove, pinned clone)

This commit is contained in:
Mika Kuns
2026-07-23 16:47:14 +02:00
committed by mika kuns
parent 54cdaf89d5
commit dea2b7db8b
8 changed files with 611 additions and 0 deletions
@@ -0,0 +1,43 @@
using ClaudeDo.Worker.Skills;
namespace ClaudeDo.Worker.Tests.Skills;
/// <summary>
/// Test double for IRepoCloner: "clones" by copying a pre-built local fixture directory,
/// so tests never touch the network or invoke real git. One fixture dir + pinned ref can
/// be registered per source URL.
/// </summary>
public sealed class FakeRepoCloner : IRepoCloner
{
private readonly Dictionary<string, (string FixtureDir, string PinnedRef)> _sources = new();
private int _cloneCount;
public int CloneCount => _cloneCount;
public void Register(string url, string fixtureDir, string pinnedRef) =>
_sources[url] = (fixtureDir, pinnedRef);
public Task<ClonedRepo> CloneAsync(string url, string destDir, CancellationToken ct)
{
_cloneCount++;
if (!_sources.TryGetValue(url, out var source))
throw new InvalidOperationException($"FakeRepoCloner has no fixture registered for '{url}'.");
CopyDirectory(source.FixtureDir, destDir);
return Task.FromResult(new ClonedRepo(destDir, source.PinnedRef));
}
private static void CopyDirectory(string sourceDir, string destDir)
{
Directory.CreateDirectory(destDir);
foreach (var file in Directory.EnumerateFiles(sourceDir, "*", SearchOption.AllDirectories))
{
var relative = Path.GetRelativePath(sourceDir, file);
var destPath = Path.Combine(destDir, relative);
var destParent = Path.GetDirectoryName(destPath);
if (!string.IsNullOrEmpty(destParent))
Directory.CreateDirectory(destParent);
File.Copy(file, destPath, overwrite: true);
}
}
}