Show plugin-provided skills in the slash picker and Skills panel - #228
Open
vladkopzon wants to merge 1 commit into
Open
vladkopzon wants to merge 1 commit into
vladkopzon wants to merge 1 commit into
Conversation
The CLI's system/init message already reports every loaded plugin in `slash_commands`, `skills`, and `plugins`, including plugins supplied on the command line with `--plugin-dir`. `_processJsonStreamData` parsed that message but forwarded only `session_id`, `tools`, and `mcp_servers` to the webview, so the rest was dropped. As a result the slash picker and the Skills panel showed only what `_loadSkills` could find by scanning `~/.claude/skills` and `<workspace>/.claude/skills`. Plugin skills live under their own plugin directory and were therefore invisible in the UI, even though they were loaded and callable by the model. Wrappers that inject plugins via `--plugin-dir` lost their whole command set this way. Changes: - Capture `slash_commands`, `skills`, and `plugins` from system/init, cache them in globalState, and include them in the sessionInfo message. - Replay the cache in `_sendCustomSnippets`, which the webview calls on load, so the picker is populated before the first message of a session. - Merge plugin-provided skills into `_loadSkills`, reading each SKILL.md from its plugin directory for the description and body. - Render plugin commands in the picker reusing the existing `.slash-command-item` markup, so the search filter works unchanged. - Hide "Delete" on plugin skills; they are not managed by this extension and deleting them would target the wrong directory. Skill ids without a `plugin:skill` prefix are treated as built-ins and skipped, so nothing already listed is duplicated.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Skills and commands contributed by plugins never appear in the UI — not in the slash picker, not in the Skills panel — even though they are loaded and callable by the model.
This is most visible with plugins supplied on the command line via
--plugin-dir(wrappers that inject a toolkit this way lose their entire command set), but it applies to any plugin-provided skill, since those live under the plugin's own directory rather than~/.claude/skills.Root cause
The CLI already tells us everything we need. Its
system/initmessage carries:{ "type": "system", "subtype": "init", "slash_commands": ["hsd:hsd", "myplugin:setup", "dataviz", ...], "skills": ["hsd:hsd", "myplugin:setup", ...], "plugins": [{ "name": "myplugin", "path": "/path/to/plugin", "source": "..." }], ... }_processJsonStreamDataparses that message but forwards onlysession_id,tools, andmcp_serversintosessionInfo. The remaining fields are dropped.The UI is then left with
_loadSkills, which only scans~/.claude/skillsand<workspace>/.claude/skills. Plugin skills are in neither, so they are invisible.Changes
slash_commands,skills, andpluginsfromsystem/init, cache them inglobalState, and include them in thesessionInfomessage._sendCustomSnippets, which the webview calls on load. Without this the picker stays empty until the first message of a session, sincesystem/inithasn't arrived yet._loadSkills, reading eachSKILL.mdfrom its plugin directory for the description and body..slash-command-itemmarkup sofilterSlashCommands()works unchanged.deleteSkillwould target the wrong directory.Skill ids without a
plugin:skillprefix are treated as built-ins and skipped, so nothing already listed is duplicated. Everything is defensive: if the fields are absent, behaviour is exactly as before.There is a second
sessionInfoemitter incase 'result'. It carries noslash_commands, and the webview hook is guarded byif (message.data.slashCommands), so it skips rather than clearing the rendered list.Testing
tsc -p ./— clean, 0 errorseslint src— 25 warnings, byte-identical to the pre-change baseline; this PR adds nonevm.Script(the injected code lives inside thegetScripttemplate literal, so it deliberately avoids backticks and${})['dataviz','myplugin:setup','hsd:hsd','loop','eqvcheck:eqvcheck',null,42]it emits exactly the threeplugin:skillentries, sorted and HTML-escaped, with built-ins and non-strings filtered out--plugin-dir: all six appear in the picker and the Skills panel, click inserts/plugin:skillinto the input, and search filters them correctly