From f80d2c8365c1b7944a1311e703cc7615fc06edd9 Mon Sep 17 00:00:00 2001 From: dyoshikawa Date: Mon, 22 Jun 2026 04:01:19 -0700 Subject: [PATCH] fix(rovodev): preserve skill compatibility frontmatter on round-trip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RovodevSkillFrontmatterSchema declared name/description/allowed-tools/license/ metadata but not compatibility, and toRulesyncSkill/fromRulesyncSkill map fields explicitly, so the documented optional Agent Skills compatibility field was silently dropped on round-trip (a residual of #1696). Add compatibility (free-form string, object form accepted for back-compat) to RovodevSkillFrontmatterSchema and the rulesync skill rovodev section, and carry it through both round-trip mappings — mirroring the agentsskills/vibe adapters. Refs #1986 Co-Authored-By: Claude Opus 4.8 --- docs/reference/file-formats.md | 1 + skills/rulesync/file-formats.md | 1 + src/features/skills/rovodev-skill.test.ts | 3 +++ src/features/skills/rovodev-skill.ts | 9 +++++++++ src/features/skills/rulesync-skill.ts | 4 ++++ 5 files changed, 18 insertions(+) diff --git a/docs/reference/file-formats.md b/docs/reference/file-formats.md index 3e2eae221..1276156a0 100644 --- a/docs/reference/file-formats.md +++ b/docs/reference/file-formats.md @@ -488,6 +488,7 @@ copilotcli: # for GitHub Copilot CLI-specific parameters (optional; project .git rovodev: # for Rovo Dev CLI-specific parameters (optional; Agent Skills standard) allowed-tools: "grep bash" # (optional) space-separated string (a YAML list is also accepted) license: MIT # (optional) + compatibility: "Requires Python 3.14+ and uv" # (optional) free-form string (object form also accepted) metadata: # (optional) free-form metadata author: rulesync zed: # for Zed-specific parameters (optional) diff --git a/skills/rulesync/file-formats.md b/skills/rulesync/file-formats.md index 3e2eae221..1276156a0 100644 --- a/skills/rulesync/file-formats.md +++ b/skills/rulesync/file-formats.md @@ -488,6 +488,7 @@ copilotcli: # for GitHub Copilot CLI-specific parameters (optional; project .git rovodev: # for Rovo Dev CLI-specific parameters (optional; Agent Skills standard) allowed-tools: "grep bash" # (optional) space-separated string (a YAML list is also accepted) license: MIT # (optional) + compatibility: "Requires Python 3.14+ and uv" # (optional) free-form string (object form also accepted) metadata: # (optional) free-form metadata author: rulesync zed: # for Zed-specific parameters (optional) diff --git a/src/features/skills/rovodev-skill.test.ts b/src/features/skills/rovodev-skill.test.ts index 2afba73f9..22ac9c51b 100644 --- a/src/features/skills/rovodev-skill.test.ts +++ b/src/features/skills/rovodev-skill.test.ts @@ -295,6 +295,7 @@ body`, description: "Desc", "allowed-tools": "grep bash", license: "MIT", + compatibility: "Requires Python 3.14+ and uv", metadata: { author: "rulesync" }, }, body: "Body", @@ -305,6 +306,7 @@ body`, expect(rulesync.getFrontmatter().rovodev).toEqual({ "allowed-tools": "grep bash", license: "MIT", + compatibility: "Requires Python 3.14+ and uv", metadata: { author: "rulesync" }, }); @@ -317,6 +319,7 @@ body`, const fm = roundTripped.getFrontmatter(); expect(fm["allowed-tools"]).toBe("grep bash"); expect(fm.license).toBe("MIT"); + expect(fm.compatibility).toBe("Requires Python 3.14+ and uv"); expect(fm.metadata).toEqual({ author: "rulesync" }); }); }); diff --git a/src/features/skills/rovodev-skill.ts b/src/features/skills/rovodev-skill.ts index 5937dfc93..1d4c5792f 100644 --- a/src/features/skills/rovodev-skill.ts +++ b/src/features/skills/rovodev-skill.ts @@ -27,6 +27,9 @@ export const RovodevSkillFrontmatterSchema = z.looseObject({ // https://support.atlassian.com/rovo/docs/extend-rovo-dev-cli-with-agent-skills/ "allowed-tools": z.optional(z.union([z.string(), z.array(z.string())])), license: z.optional(z.string()), + // The Agent Skills spec defines `compatibility` as a free-form string + // (1–500 chars); the object form stays accepted for back-compat. + compatibility: z.optional(z.union([z.string(), z.looseObject({})])), metadata: z.optional(z.looseObject({})), }); @@ -138,6 +141,9 @@ export class RovodevSkill extends ToolSkill { "allowed-tools": frontmatter["allowed-tools"], }), ...(frontmatter.license !== undefined && { license: frontmatter.license }), + ...(frontmatter.compatibility !== undefined && { + compatibility: frontmatter.compatibility, + }), ...(frontmatter.metadata !== undefined && { metadata: frontmatter.metadata }), }; const rulesyncFrontmatter: RulesyncSkillFrontmatterInput = { @@ -176,6 +182,9 @@ export class RovodevSkill extends ToolSkill { "allowed-tools": rovodevSection["allowed-tools"], }), ...(rovodevSection?.license !== undefined && { license: rovodevSection.license }), + ...(rovodevSection?.compatibility !== undefined && { + compatibility: rovodevSection.compatibility, + }), ...(rovodevSection?.metadata !== undefined && { metadata: rovodevSection.metadata }), }; diff --git a/src/features/skills/rulesync-skill.ts b/src/features/skills/rulesync-skill.ts index 8914f4396..55b9422bf 100644 --- a/src/features/skills/rulesync-skill.ts +++ b/src/features/skills/rulesync-skill.ts @@ -136,6 +136,9 @@ const RulesyncSkillFrontmatterSchemaInternal = z.looseObject({ z.looseObject({ "allowed-tools": z.optional(z.union([z.string(), z.array(z.string())])), license: z.optional(z.string()), + // The Agent Skills spec defines `compatibility` as a free-form string + // (1–500 chars); the object form stays accepted for back-compat. + compatibility: z.optional(z.union([z.string(), z.looseObject({})])), metadata: z.optional(z.looseObject({})), }), ), @@ -268,6 +271,7 @@ export type RulesyncSkillFrontmatterInput = { rovodev?: { "allowed-tools"?: string | string[]; license?: string; + compatibility?: string | Record; metadata?: Record; }; cursor?: {