From 5952147376c69ec88d8942a9531c8886501cef49 Mon Sep 17 00:00:00 2001 From: sjhddh Date: Wed, 8 Apr 2026 18:55:47 +0200 Subject: [PATCH 1/2] fix: handle empty skill_intro in skill_description generation When a harness has no README.md, skill_intro is an empty string. The previous code unconditionally appended " - ..." producing malformed output like "Command-line interface for TestApp - ..." in SKILL.md YAML frontmatter. Also fixed: when skill_intro is non-empty but <=100 chars, no ellipsis is appended (previously appended to complete text). Applied the same fix to both: - cli-anything-plugin/skill_generator.py (line 118) - mubu/agent-harness/skill_generator.py (line 238) Updated test_harness_without_readme to assert skill_description is well-formed when intro is empty. Co-Authored-By: Claude Sonnet 4.6 --- cli-anything-plugin/skill_generator.py | 13 ++++++++++--- cli-anything-plugin/tests/test_skill_generator.py | 3 +++ mubu/agent-harness/skill_generator.py | 11 +++++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/cli-anything-plugin/skill_generator.py b/cli-anything-plugin/skill_generator.py index ecf14c089..de2d9a6a7 100644 --- a/cli-anything-plugin/skill_generator.py +++ b/cli-anything-plugin/skill_generator.py @@ -115,7 +115,12 @@ def extract_cli_metadata(harness_path: str) -> SkillMetadata: # Build skill name and description skill_name = f"cli-anything-{software_name}" - skill_description = f"Command-line interface for {_format_display_name(software_name)} - {skill_intro[:100]}..." + if skill_intro: + intro_snippet = skill_intro[:100] + suffix = "..." if len(skill_intro) > 100 else "" + skill_description = f"Command-line interface for {_format_display_name(software_name)} - {intro_snippet}{suffix}" + else: + skill_description = f"Command-line interface for {_format_display_name(software_name)}" return SkillMetadata( skill_name=skill_name, @@ -159,14 +164,16 @@ def extract_system_package(content: str) -> Optional[str]: patterns = [ r"`apt install ([\w\-]+)`", r"`brew install ([\w\-]+)`", - r"apt-get install ([\w\-]+)", + r"`apt-get install ([\w\-]+)`", ] for pattern in patterns: match = re.search(pattern, content) if match: package = match.group(1) - if "apt" in pattern: + if "apt-get" in pattern: + return f"apt-get install {package}" + elif "apt" in pattern: return f"apt install {package}" elif "brew" in pattern: return f"brew install {package}" diff --git a/cli-anything-plugin/tests/test_skill_generator.py b/cli-anything-plugin/tests/test_skill_generator.py index dec23e868..b3cc25304 100644 --- a/cli-anything-plugin/tests/test_skill_generator.py +++ b/cli-anything-plugin/tests/test_skill_generator.py @@ -326,6 +326,9 @@ class TestEdgeCases: assert metadata.skill_intro == "" # No README → empty intro assert metadata.version == "1.0.0" assert metadata.command_groups == [] + # skill_description must not contain trailing " - ..." when intro is empty + assert " - " not in metadata.skill_description + assert not metadata.skill_description.endswith("...") def test_harness_with_system_package(self, tmp_path): """README with apt install instructions should extract system_package.""" diff --git a/mubu/agent-harness/skill_generator.py b/mubu/agent-harness/skill_generator.py index 3e1a62749..7f9327892 100644 --- a/mubu/agent-harness/skill_generator.py +++ b/mubu/agent-harness/skill_generator.py @@ -76,13 +76,15 @@ def extract_system_package(content: str) -> Optional[str]: patterns = [ r"`apt install ([\w\-]+)`", r"`brew install ([\w\-]+)`", - r"apt-get install ([\w\-]+)", + r"`apt-get install ([\w\-]+)`", ] for pattern in patterns: match = re.search(pattern, content) if match: package = match.group(1) + if "apt-get" in pattern: + return f"apt-get install {package}" if "apt" in pattern: return f"apt install {package}" if "brew" in pattern: @@ -235,7 +237,12 @@ def extract_cli_metadata(harness_path: str) -> SkillMetadata: command_groups = extract_commands_from_cli(cli_file) if cli_file.exists() else [] examples = generate_examples(software_name, command_groups) skill_name = f"cli-anything-{software_name}" - skill_description = f"Command-line interface for {_format_display_name(software_name)} - {skill_intro[:100]}..." + if skill_intro: + intro_snippet = skill_intro[:100] + suffix = "..." if len(skill_intro) > 100 else "" + skill_description = f"Command-line interface for {_format_display_name(software_name)} - {intro_snippet}{suffix}" + else: + skill_description = f"Command-line interface for {_format_display_name(software_name)}" return SkillMetadata( skill_name=skill_name, From 1a93cce183b0ce0bb129c8b68afeae52a24bb383 Mon Sep 17 00:00:00 2001 From: sjhddh Date: Sun, 12 Apr 2026 23:34:47 +0200 Subject: [PATCH 2/2] refactor: remove extract_system_package changes (split to #204) Co-Authored-By: Claude Opus 4.6 --- cli-anything-plugin/skill_generator.py | 6 ++---- mubu/agent-harness/skill_generator.py | 4 +--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/cli-anything-plugin/skill_generator.py b/cli-anything-plugin/skill_generator.py index de2d9a6a7..fe7cc7907 100644 --- a/cli-anything-plugin/skill_generator.py +++ b/cli-anything-plugin/skill_generator.py @@ -164,16 +164,14 @@ def extract_system_package(content: str) -> Optional[str]: patterns = [ r"`apt install ([\w\-]+)`", r"`brew install ([\w\-]+)`", - r"`apt-get install ([\w\-]+)`", + r"apt-get install ([\w\-]+)", ] for pattern in patterns: match = re.search(pattern, content) if match: package = match.group(1) - if "apt-get" in pattern: - return f"apt-get install {package}" - elif "apt" in pattern: + if "apt" in pattern: return f"apt install {package}" elif "brew" in pattern: return f"brew install {package}" diff --git a/mubu/agent-harness/skill_generator.py b/mubu/agent-harness/skill_generator.py index 7f9327892..a1c070f7c 100644 --- a/mubu/agent-harness/skill_generator.py +++ b/mubu/agent-harness/skill_generator.py @@ -76,15 +76,13 @@ def extract_system_package(content: str) -> Optional[str]: patterns = [ r"`apt install ([\w\-]+)`", r"`brew install ([\w\-]+)`", - r"`apt-get install ([\w\-]+)`", + r"apt-get install ([\w\-]+)", ] for pattern in patterns: match = re.search(pattern, content) if match: package = match.group(1) - if "apt-get" in pattern: - return f"apt-get install {package}" if "apt" in pattern: return f"apt install {package}" if "brew" in pattern: