diff --git a/server/skillhub-app/src/main/java/com/iflytek/skillhub/service/SkillPackagePreviewService.java b/server/skillhub-app/src/main/java/com/iflytek/skillhub/service/SkillPackagePreviewService.java index 252c176bb..41d354a81 100644 --- a/server/skillhub-app/src/main/java/com/iflytek/skillhub/service/SkillPackagePreviewService.java +++ b/server/skillhub-app/src/main/java/com/iflytek/skillhub/service/SkillPackagePreviewService.java @@ -32,7 +32,7 @@ public class SkillPackagePreviewService { SkillMetadata metadata = parser.parse(new String(skillMd.content(), StandardCharsets.UTF_8)); SkillExamplesSummary examples = SkillExamplesSummary.recognize(entries); return new SkillPackagePreviewResponse(metadata.name(), metadata.displayName(), metadata.description(), - metadata.shortDescription(), metadata.overview(), metadata.version(), + metadata.shortDescription(), metadata.packageOverview(), metadata.version(), examples.status(), examples.count()); } } diff --git a/server/skillhub-app/src/test/java/com/iflytek/skillhub/service/SkillPackagePreviewServiceTest.java b/server/skillhub-app/src/test/java/com/iflytek/skillhub/service/SkillPackagePreviewServiceTest.java index c1a2bbc77..3f963690b 100644 --- a/server/skillhub-app/src/test/java/com/iflytek/skillhub/service/SkillPackagePreviewServiceTest.java +++ b/server/skillhub-app/src/test/java/com/iflytek/skillhub/service/SkillPackagePreviewServiceTest.java @@ -42,6 +42,39 @@ class SkillPackagePreviewServiceTest { assertThat(serialized).contains("\"version\":null"); } + @Test + void missingOverviewStaysNullSoTheClientCanResolvePackageDocumentation() throws Exception { + var files = new java.util.ArrayList<>(entries("")); + byte[] readme = "# User-facing README".getBytes(StandardCharsets.UTF_8); + files.add(new PackageEntry("README.md", readme, readme.length, "text/markdown")); + + var response = service.preview(files); + + assertThat(response.overview()).isNull(); + assertThat(response.description()).isEqualTo("Summary"); + assertThat(response.shortDescription()).isEqualTo("Summary"); + assertThat(response.examplesCount()).isZero(); + assertThat(new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(response)) + .contains("\"overview\":null"); + assertThat(files.get(0).content()).containsExactly(entries("").get(0).content()); + assertThat(files.get(1).content()).containsExactly(readme); + } + + @Test + void explicitPackageOverviewIsReturnedWithoutUsingTheSkillBody() { + var response = service.preview(entries("metadata:\n overview: ' Package overview '\n")); + + assertThat(response.overview()).isEqualTo("Package overview"); + } + + @Test + void blankPackageOverviewDoesNotBecomeTheSkillBody() { + for (String metadata : List.of("metadata: {}\n", "metadata:\n overview: null\n", + "metadata:\n overview: ' '\n")) { + assertThat(service.preview(entries(metadata)).overview()).isNull(); + } + } + @Test void examplesRecognitionIsNonBlockingAndOmitsInvalidCount() throws Exception { assertThat(service.preview(entries("")).examplesCount()).isZero(); diff --git a/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/metadata/SkillMetadata.java b/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/metadata/SkillMetadata.java index c4a546e06..60a163720 100644 --- a/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/metadata/SkillMetadata.java +++ b/server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/metadata/SkillMetadata.java @@ -57,10 +57,15 @@ public record SkillMetadata( } public String overview() { - String packageOverview = nestedText(frontmatter, "overview", null); + String packageOverview = packageOverview(); return overviewOverride != null ? overviewOverride : (packageOverview != null ? packageOverview : body); } + /** Explicit package presentation only; documentation fallback is resolved by the reader. */ + public String packageOverview() { + return nestedText(frontmatter, "overview", null); + } + private static String nestedText(Map values, String key, String fallback) { if (values != null && values.get("metadata") instanceof Map metadata && metadata.get(key) instanceof String text && !text.strip().isEmpty()) { diff --git a/server/skillhub-domain/src/test/java/com/iflytek/skillhub/domain/skill/metadata/SkillMetadataParserTest.java b/server/skillhub-domain/src/test/java/com/iflytek/skillhub/domain/skill/metadata/SkillMetadataParserTest.java index 5cf3e2aa6..eb42a5909 100644 --- a/server/skillhub-domain/src/test/java/com/iflytek/skillhub/domain/skill/metadata/SkillMetadataParserTest.java +++ b/server/skillhub-domain/src/test/java/com/iflytek/skillhub/domain/skill/metadata/SkillMetadataParserTest.java @@ -11,6 +11,22 @@ class SkillMetadataParserTest { private final SkillMetadataParser parser = new SkillMetadataParser(); + @Test + void packageOverviewDoesNotIncludeOverridesOrBodyFallback() { + SkillMetadata declared = parser.parse("---\nname: my-skill\ndescription: Original\nmetadata:\n overview: ' Package overview '\n---\nBody"); + assertEquals("Package overview", declared.packageOverview()); + assertEquals("Package overview", declared.withPresentation(null, "Web overview", null).packageOverview()); + for (Map frontmatter : java.util.List.of(Map.of(), + Map.of("metadata", Map.of("overview", " ")), + Map.of("metadata", Map.of("overview", 123)), + Map.of("metadata", "legacy"))) { + SkillMetadata metadata = new SkillMetadata("my-skill", "Summary", "1.0.0", "Body", frontmatter); + assertNull(metadata.packageOverview()); + assertEquals("Body", metadata.overview()); + } + assertNull(new SkillMetadata("my-skill", "Summary", "1.0.0", "Body", null).packageOverview()); + } + @Test void presentationOverridesAndPackageDefaultsRemainDistinct() { SkillMetadata source = parser.parse("---\nname: my-skill\ndescription: Original\nmetadata:\n short-description: Package short\n overview: Package overview\n---\nBody");