* feat(tui): implement completion popup rendering and windowing logic
* feat(tui): enhance completion popup with dynamic row budgeting and CSS adjustments
* Refactor picker widgets to use shared base class for improved code reuse
- Introduced `picker_base.py` to encapsulate common functionality for picker widgets.
- Updated `ModelPickerWidget`, `SkillBrowserWidget`, and `ThreadPickerWidget` to inherit from `PickerWidgetBase`.
- Implemented selection helpers (`first_selectable_index`, `move_selection`) in `picker_base.py` for consistent item navigation.
- Refactored rendering and selection logic in each widget to utilize the new base class methods.
- Added tests for picker functionality to ensure behavior remains consistent post-refactor.
- Fix RUF006: Implement background task tracking in Discord, iMessage, WeChat, and TUI to prevent premature GC of fire-and-forget tasks.
- Fix B904: Add explicit exception chaining (raise ... from) across all exception handlers.
- Fix RUF012: Annotate mutable class attributes with ClassVar for command arguments and media maps.
- Fix B008: Refactor Typer commands in cli/commands.py to use Annotated for argument and option defaults.
- Fix B023/B018: Resolve late-binding issues in lambdas and remove useless expressions.
- Fix syntax errors in retry.py docstrings and models.py lambda parameter ordering.
* refactor(mcp): extract MCP server registry from onboard into shared module
Move _RECOMMENDED_MCP_SERVERS, _install_pip_package, and
_pip_install_hint from config/onboard.py into mcp/registry.py as a
shared MCPServerEntry dataclass and registry functions. This enables
reuse by the new /install-mcp command and marketplace integration.
* feat(mcp): add /install-mcp command for browsing and installing MCP servers
Interactive browser for MCP servers (built-in registry + EvoSkills
marketplace), supporting three modes:
- /install-mcp — interactive tag filter + checkbox selection
- /install-mcp <name> — direct install by name or tag pre-filter
- /install-mcp file.yaml — import servers from arbitrary YAML file
Also available as /mcp install and EvoSci mcp install. Includes TUI
browser widget (MCPBrowserWidget) mirroring the skill browser UX.
* chore(tavily): conditionally pass tavily_search when TAVILY_API_KEY is set
* fix(tui): Enter key detection for /install-mcp
- Fix message handler names: Textual converts MCPBrowserWidget to
mcpbrowser_widget (not mcp_browser_widget), so Confirmed/Cancelled
messages were never received by the app
- Distinguish empty selection from cancel in result handling
* chore(widgets): stop auto-advancing cursor on Space toggle in browser widgets
* style: linter
* refactor(mcp): simplify MCP registry to marketplace-only
Remove built-in server list and arbitrary YAML import — all server
definitions now come from the EvoSkills marketplace (mcp/*.yaml).
Onboarding filters by the `onboarding` tag instead of a hardcoded list.
* refactor(mcp): consolidate /install-mcp into /mcp install
Remove standalone /install-mcp command — use /mcp install as the
single entry point. CLI adapter now delegates logic to the shared
InstallMCPCommand class, keeping only the questionary UI layer.
* chore(cli): rm reference to yaml import
* 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