2f855c07c7
* feat: add tag support to skill metadata parser - Add `tags` field to `SkillInfo` dataclass - Extend `_parse_skill_md` to return `SkillInfo` directly (instead of dict), extracting tags from top-level `tags` or `metadata.tags` fallback - Accept `source` as keyword argument in `_parse_skill_md` to avoid post-hoc mutation - Add `_normalize_tags` helper (handles list, comma-string, missing) - Add `list_skills_by_tag()` for filtering installed skills by tag - Add `get_all_tags()` returning tags sorted by count then alphabetically - Add `fetch_remote_skill_index()` with shallow-clone and 10-min cache - Add 12 new tests covering tag parsing, filtering, and remote index * feat: add /install-skills command and browse action to skill_manager tool CLI: - Add `/install-skills` slash command with interactive tag picker and skill checkbox (questionary-based, for CLI mode) - Accepts optional tag argument for pre-filtering: `/install-skills core` - Update `/skills` listing to show tags per skill - Register command in interactive.py dispatch LangChain tool: - Add `browse` action to `skill_manager` tool with optional `tag` filter - Update `list` and `info` actions to include tags in output * feat: add interactive skill browser widget for TUI New widget (skill_browser.py): - Two-phase keyboard-driven widget mounted inline in chat - Phase 1: tag picker (arrow keys + Enter, Esc to cancel) - Phase 2: skill checkbox (Space to toggle, Enter to install, Esc back) - Width-aware description truncation with ellipsis - Installed skills shown as non-toggleable with checkmark TUI integration (tui_interactive.py): - Register /install-skills command with async widget flow - Echo executed commands in cyan before output - Add SkillBrowserWidget keyboard delegation (up/down/esc) - Refocus prompt input after any widget dismissal (also fixes pre-existing /resume and /delete focus bug) - Show tags as bulleted newlines in /skills table - Dynamic autocomplete padding based on longest item