AtomiCloud

writing-resolver-dotnet

编写或修改 CyanPrint 的 C# 冲突解析器代码,处理来自多个模板的相同路径文件之间的冲突。涵盖入口点、输入输出类型、FileOrigin,并确保结果不受输入顺序影响。

AtomiCloud 0 更新于 5个月前
GitHub

安装

npx skillscat add atomicloud/ketone-new-cyanprint/writing-resolver-dotnet

通过 SkillsCat registry 安装。

技能简介

编写或修改 CyanPrint 的 C# 冲突解析器代码,处理来自多个模板的相同路径文件之间的冲突。涵盖入口点、输入输出类型、FileOrigin,并确保结果不受输入顺序影响。

SKILL.md

Writing this Resolver (C# / .NET)

Entry Point

using sulfone_helium;

ResolverOutput ResolverFn(ResolverInput input)
{
    // Resolve conflict
    return new ResolverOutput { Path = path, Content = content };
}

CyanEngine.StartResolver(ResolverFn);

ResolverInput

public class ResolverInput
{
    public Dictionary<string, object> Config { get; set; }
    public List<ResolvedFile> Files { get; set; }
}

ResolvedFile

All Files entries have the same Path -- that is the conflict being resolved:

public class ResolvedFile
{
    public string Path { get; set; }
    public string Content { get; set; }
    public FileOrigin Origin { get; set; }
}

FileOrigin

public class FileOrigin
{
    public string Template { get; set; }  // Which template produced this file
    public int Layer { get; set; }        // Layer number -- IMPORTANT: int, NOT string
}

Critical: Layer is an int, not a string. Compare numerically, never as string.

ResolverOutput

Return a single resolved file:

public class ResolverOutput
{
    public string Path { get; set; }
    public string Content { get; set; }
}

Commutativity and Associativity

CyanPrint may call the resolver with files in any order. Your result must be identical regardless of input ordering.

Pattern 1: Sort before processing

var sorted = input.Files
    .OrderBy(f => f.Origin.Layer)
    .ThenBy(f => f.Origin.Template)
    .ToList();

Pattern 2: Deduplicate after merge

var allItems = sorted
    .SelectMany(f => JsonSerializer.Deserialize<List<string>>(f.Content))
    .Distinct()
    .OrderBy(x => x)
    .ToList();

Pattern 3: Deterministic priority

// Highest layer number wins -- deterministic regardless of input order
var winner = input.Files.OrderByDescending(f => f.Origin.Layer).First();

Resolution Strategies

Last-Write Wins (by layer)

var sorted = input.Files
    .OrderBy(f => f.Origin.Layer)
    .ThenBy(f => f.Origin.Template)
    .ToList();
var last = sorted.Last();
return new ResolverOutput { Path = last.Path, Content = last.Content };

Deep Merge (JSON)

var sorted = input.Files
    .OrderBy(f => f.Origin.Layer)
    .ThenBy(f => f.Origin.Template)
    .ToList();
var merged = new Dictionary<string, object>();
foreach (var file in sorted)
{
    merged = DeepMerge(merged, JsonSerializer.Deserialize<Dictionary<string, object>>(file.Content));
}
return new ResolverOutput
{
    Path = input.Files[0].Path,
    Content = JsonSerializer.Serialize(merged, new JsonSerializerOptions { WriteIndented = true })
};

Entry Point Skeleton

using sulfone_helium;

ResolverOutput ResolverFn(ResolverInput input)
{
    var files = input.Files;
    if (files.Count == 0) throw new Exception("Resolver received no files — at least 1 file is required");
    var uniquePaths = files.Select(f => f.Path).Distinct().ToList();
    if (uniquePaths.Count > 1) throw new Exception($"Resolver received files with different paths: {string.Join(", ", uniquePaths)} — all files must have the same path");
    var path = files[0].Path;

    // Sort for commutativity (layer ascending, then template name)
    var sorted = files
        .OrderBy(f => f.Origin.Layer)
        .ThenBy(f => f.Origin.Template)
        .ToList();

    // TODO: Implement resolution logic
    var content = sorted.Last().Content;

    return new ResolverOutput { Path = path, Content = content };
}

CyanEngine.StartResolver(ResolverFn);

Key Rules

  1. All Files entries have the same Path -- that is the conflict being resolved
  2. FileOrigin.Layer is an int -- compare numerically, never as string
  3. Return a single new ResolverOutput { Path = ..., Content = ... } -- the resolved file
  4. Ensure commutativity -- sort inputs before processing, deduplicate outputs
  5. Ensure associativity -- result must be same whether resolved all-at-once or in pairs
  6. Validate input -- reject empty files list and mismatched paths with an error