diff --git a/docs/syntax/agent-skill.md b/docs/syntax/agent-skill.md index 838b47ae0..19820f245 100644 --- a/docs/syntax/agent-skill.md +++ b/docs/syntax/agent-skill.md @@ -1,6 +1,6 @@ # Agent skill -The `{agent-skill}` directive renders a standardized callout that points readers to an [Elastic AI agent skill](https://github.com/elastic/agent-skills). When the URL includes a skill name (after `@`), it shows a "Copy install command" button that copies the `npx skills add @skill-name` command to clipboard. Otherwise, it falls back to a "Get the skill" link. +The `{agent-skill}` directive renders a standardized callout that points readers to an [Elastic AI agent skill](https://github.com/elastic/agent-skills). When the URL includes a skill name (after `@`), it shows a "Copy install command" button that copies the `npx skills add owner/repo@skill-name` command to clipboard. Otherwise, it falls back to a "Get the skill" link. ## Usage @@ -64,4 +64,4 @@ This skill helps agents write and optimize ES|QL queries. The `:url:` property must be an absolute URL. Relative paths are not accepted, and the directive will emit a build error if the URL is missing or relative. -The skill name is extracted from the URL as the segment after the final `@`. For example, `https://github.com/elastic/agent-skills@elasticsearch-esql` produces the install command `npx skills add @elasticsearch-esql`. +The skill name is extracted from the URL as the segment after the final `@`, and the repository prefix is extracted from the URL path. For example, `https://github.com/elastic/agent-skills@elasticsearch-esql` produces the install command `npx skills add elastic/agent-skills@elasticsearch-esql`. diff --git a/src/Elastic.Markdown/Myst/Directives/AgentSkill/AgentSkillBlock.cs b/src/Elastic.Markdown/Myst/Directives/AgentSkill/AgentSkillBlock.cs index 8d4b152e0..333e0af4c 100644 --- a/src/Elastic.Markdown/Myst/Directives/AgentSkill/AgentSkillBlock.cs +++ b/src/Elastic.Markdown/Myst/Directives/AgentSkill/AgentSkillBlock.cs @@ -15,7 +15,11 @@ public class AgentSkillBlock(DirectiveBlockParser parser, ParserContext context) public string? SkillName { get; private set; } - public string? InstallCommand => SkillName is not null ? $"npx skills add @{SkillName}" : null; + public string? RepoPrefix { get; private set; } + + public string? InstallCommand => SkillName is not null && RepoPrefix is not null + ? $"npx skills add {RepoPrefix}@{SkillName}" + : null; public override void FinalizeAndValidate(ParserContext context) { @@ -25,17 +29,24 @@ public override void FinalizeAndValidate(ParserContext context) else if (!Uri.TryCreate(Url, UriKind.Absolute, out var uri) || uri.Scheme is not ("http" or "https")) this.EmitError($"agent-skill :url: must be an absolute URL, got '{Url}'"); else - SkillName = ExtractSkillName(uri); + (RepoPrefix, SkillName) = ExtractSkillParts(uri); } - private static string? ExtractSkillName(Uri uri) + private static (string? RepoPrefix, string? SkillName) ExtractSkillParts(Uri uri) { var path = uri.AbsolutePath.TrimEnd('/'); var atIndex = path.LastIndexOf('@'); if (atIndex < 0) - return null; + return (null, null); var name = path[(atIndex + 1)..]; - return string.IsNullOrWhiteSpace(name) ? null : name; + if (string.IsNullOrWhiteSpace(name)) + return (null, null); + + var repoPath = path[1..atIndex].TrimEnd('/'); + if (string.IsNullOrWhiteSpace(repoPath)) + return (null, null); + + return (repoPath, name); } } diff --git a/tests/Elastic.Markdown.Tests/Directives/AgentSkillTests.cs b/tests/Elastic.Markdown.Tests/Directives/AgentSkillTests.cs index eeb772fc1..df55897c5 100644 --- a/tests/Elastic.Markdown.Tests/Directives/AgentSkillTests.cs +++ b/tests/Elastic.Markdown.Tests/Directives/AgentSkillTests.cs @@ -26,7 +26,7 @@ A regular paragraph. public void SetsSkillName() => Block!.SkillName.Should().Be("elasticsearch-esql"); [Fact] - public void SetsInstallCommand() => Block!.InstallCommand.Should().Be("npx skills add @elasticsearch-esql"); + public void SetsInstallCommand() => Block!.InstallCommand.Should().Be("npx skills add elastic/agent-skills@elasticsearch-esql"); [Fact] public void SetsDirective() => Block!.Directive.Should().Be("agent-skill"); @@ -59,7 +59,7 @@ public void RendersCopyButton() { Html.Should().Contain("class=\"agent-skill-button\""); Html.Should().Contain("Copy install command"); - Html.Should().Contain("data-copy-text=\"npx skills add @elasticsearch-esql\""); + Html.Should().Contain("data-copy-text=\"npx skills add elastic/agent-skills@elasticsearch-esql\""); } [Fact] diff --git a/tests/authoring/Blocks/AgentSkill.fs b/tests/authoring/Blocks/AgentSkill.fs index adadb9c86..e698781f9 100644 --- a/tests/authoring/Blocks/AgentSkill.fs +++ b/tests/authoring/Blocks/AgentSkill.fs @@ -28,7 +28,7 @@ type ``agent skill with url`` () =
A skill is available to help AI agents with this topic.
-