diff --git a/main.py b/main.py index 19f6ff0..d439669 100644 --- a/main.py +++ b/main.py @@ -262,6 +262,18 @@ def ai_handler(msg: IncomingMessage) -> str: if name: return _create_skill_from_description(name, description) + # Detect natural language skill rename requests + _SKILL_RENAME_RE = re.compile( + r"rename\s+(?:the\s+)?(?:this\s+)?(?:skill\s+)?(.+?)\s+to\s+(.+)", + re.IGNORECASE, + ) + rename_match = _SKILL_RENAME_RE.match(text_lower) + if rename_match: + old_name = rename_match.group(1).strip() + new_name = rename_match.group(2).strip().lower().replace(" ", "-") + if old_name and new_name: + return _handle_skill_command(f"skill rename {old_name} {new_name}") + # Build context from memory + skills context = _build_context(msg) @@ -1112,6 +1124,50 @@ def _handle_skill_command(text: str) -> str: _skills.reload() return f"✅ Skill `{name}` removed." + elif subcommand == "rename" and len(parts) >= 3: + # Parse: skill rename OR skill rename to + rename_args = parts[2].strip() + rename_parts = re.split(r"\s+to\s+|\s+", rename_args, maxsplit=1) + if len(rename_parts) < 2: + return "Usage: `skill rename `" + old_name = rename_parts[0].strip() + new_name = rename_parts[1].strip().lower().replace(" ", "-") + + cfg = load_config() + workspace = os.path.expanduser(cfg.memory.workspace) + old_dir = os.path.join(workspace, "skills", old_name) + new_dir = os.path.join(workspace, "skills", new_name) + + if not os.path.isdir(old_dir): + return f"⚠️ Skill `{old_name}` not found. Run `skill list` to see available skills." + if os.path.isdir(new_dir): + return f"⚠️ Skill `{new_name}` already exists." + + import shutil + shutil.move(old_dir, new_dir) + + # Update the name field inside SKILL.md + skill_path = os.path.join(new_dir, "SKILL.md") + if os.path.isfile(skill_path): + try: + with open(skill_path, "r", encoding="utf-8") as f: + content = f.read() + content = re.sub( + r"^(name:\s*).*$", + rf"\g<1>{new_name}", + content, + count=1, + flags=re.MULTILINE, + ) + with open(skill_path, "w", encoding="utf-8") as f: + f.write(content) + except Exception as e: + logger.warning(f"Failed to update name in SKILL.md: {e}") + + if _skills: + _skills.reload() + return f"✅ Skill renamed: `{old_name}` → `{new_name}`" + elif subcommand == "reload": if _skills: loaded = _skills.reload() @@ -1124,6 +1180,7 @@ def _handle_skill_command(text: str) -> str: "• `skill list` — List loaded skills\n" "• `skill show ` — Show skill content\n" "• `skill create ` — Create a new skill template\n" + "• `skill rename ` — Rename a skill\n" "• `skill remove ` — Remove a skill\n" "• `skill reload` — Reload all skills\n" "\nYou can also create skills naturally:\n"