Files
Teamup/src/Modules/TeamUp.Modules.Skills/Domain/Skill.cs
T

99 lines
3.8 KiB
C#
Raw Normal View History

using Pgvector;
using TeamUp.SharedKernel.Domain;
namespace TeamUp.Modules.Skills.Domain;
/// <summary>
/// An indexed skill atom: the projection of a SKILL.md (Git is the source of truth) into a
/// queryable Postgres + pgvector row. Identified by (SkillKey, Version).
/// </summary>
internal sealed class Skill : Entity
{
public string SkillKey { get; private set; } = null!;
public string Name { get; private set; } = null!;
public string Version { get; private set; } = null!;
public string? Summary { get; private set; }
public List<string> Roles { get; private set; } = [];
public string? Inputs { get; private set; }
public string? Outputs { get; private set; }
public List<SkillAction> Actions { get; private set; } = [];
public List<string> Tools { get; private set; } = [];
public List<string> Context { get; private set; } = [];
public List<GoldenExample> GoldenTests { get; private set; } = [];
public SkillVisibility Visibility { get; private set; }
public SkillTier MinTier { get; private set; }
public SkillStatus Status { get; private set; }
public string Body { get; private set; } = null!;
public string ContentHash { get; private set; } = null!;
public string? SourceRepo { get; private set; }
public string? SourcePath { get; private set; }
public string? SourceCommit { get; private set; }
public Vector? Embedding { get; private set; }
public DateTimeOffset IndexedAtUtc { get; private set; }
public DateTimeOffset UpdatedAtUtc { get; private set; }
private Skill()
{
}
public static Skill Create(string skillKey, string version, DateTimeOffset nowUtc) =>
new() { SkillKey = skillKey, Version = version, IndexedAtUtc = nowUtc };
/// <summary>(Re)projects a parsed manifest + body onto this row. Used for both insert and update.</summary>
public void Index(
SkillManifest manifest,
string body,
string contentHash,
string? sourceRepo,
string? sourcePath,
string? sourceCommit,
Vector? embedding,
SkillStatus status,
DateTimeOffset nowUtc)
{
Name = string.IsNullOrWhiteSpace(manifest.Name) ? manifest.Id : manifest.Name;
Version = manifest.Version;
Summary = manifest.Summary;
Roles = manifest.Roles;
Inputs = manifest.Inputs;
Outputs = manifest.Outputs;
Actions = manifest.Actions
.Select(a => new SkillAction { Name = a.Name, Risk = ParseRisk(a.Risk), Description = a.Description })
.ToList();
Tools = manifest.Tools;
Context = manifest.Context;
GoldenTests = manifest.GoldenTests;
Visibility = ParseVisibility(manifest.Visibility);
MinTier = ParseTier(manifest.MinTier);
Status = status;
Body = body;
ContentHash = contentHash;
SourceRepo = sourceRepo;
SourcePath = sourcePath;
SourceCommit = sourceCommit;
Embedding = embedding;
UpdatedAtUtc = nowUtc;
}
private static string Normalize(string value) => value.Trim().Replace("-", string.Empty).Replace("_", string.Empty);
private static ActionRisk ParseRisk(string value) => Normalize(value).ToLowerInvariant() switch
{
"draft" => ActionRisk.Draft,
"publish" => ActionRisk.Publish,
"destructive" => ActionRisk.Destructive,
_ => ActionRisk.Read,
};
private static SkillVisibility ParseVisibility(string value) =>
Normalize(value).ToLowerInvariant() is "privatetoorg" or "private" ? SkillVisibility.PrivateToOrg : SkillVisibility.Public;
private static SkillTier ParseTier(string value) => Normalize(value).ToLowerInvariant() switch
{
"team" => SkillTier.Team,
"scale" => SkillTier.Scale,
"enterprise" => SkillTier.Enterprise,
_ => SkillTier.Free,
};
}