feat(scanner): add Codex plugin marketplace discovery (#124)#151
Merged
feat(scanner): add Codex plugin marketplace discovery (#124)#151
Conversation
- Add scanCodexPluginCache() to scan ~/.codex/plugins/cache/{marketplace}/{plugin}/{version}/.codex-plugin/plugin.json
- Add readCodexMarketplaceFiles() to read marketplace.json from ~/.agents/plugins/ and .agents/plugins/ paths
- Add loadCodexEnabledMap() with lightweight TOML parser for ~/.codex/config.toml enabled/disabled state
- Wire Codex plugin scan into scanAllSkills() with name+realPath deduplication across Claude and Codex plugin providers
- Add CodexPluginManifest interface and codexPlugin metadata field to SkillInfo
- Register codex-plugin provider color (cyan) in formatter
- Add 25 tests covering cache discovery, TOML parsing, version selection, marketplace.json reading, and deduplication
…parser on section change - Replace lexicographic sort with compareSemver in scanCodexPluginCache so versions like 10.0.0 are correctly ranked above 2.0.0 - Reset currentPlugin to null in parseTomlEnabledMap when a non-[plugins.*] section header is encountered, preventing enabled/disabled values from other sections being attributed to the last matched plugin - Add test case covering semver vs lexicographic version selection
…lls type - Apply name-based deduplication consistently to Claude plugin skills in scanAllSkills (previously seenNames was populated but never checked for pluginSkills, only for codexPluginSkills) - Change CodexPluginManifest.skills type from string to string[] to match the actual plugin ecosystem schema
4 tasks
Object.keys(null) throws TypeError when plugin.json contains "mcp": null. Use != null (loose inequality) to safely guard against both null and undefined, preventing the entire scanCodexPluginCache call from crashing. Adds a regression test for the null mcp case.
… marketplace utility parseTomlEnabledMap now strips surrounding double/single quotes from section headers like [plugins."my-plugin"], so the enabled/disabled lookup matches the directory name correctly. Adds a clarifying JSDoc note to readCodexMarketplaceFiles explaining it is a catalog utility for search/install commands, not part of scanAllSkills.
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.
Closes #124
Summary
scanCodexPluginCache()to discover installed Codex plugins from~/.codex/plugins/cache/{marketplace}/{plugin}/{version}/.codex-plugin/plugin.jsonreadCodexMarketplaceFiles()to read available plugins from~/.agents/plugins/marketplace.jsonand.agents/plugins/marketplace.jsonloadCodexEnabledMap()with a lightweight TOML parser for~/.codex/config.tomlenabled/disabled state (no new dependencies)scanAllSkills()alongside the existing Claude plugin marketplace scanApproach
Follows the established
scanPluginMarketplaces()pattern exactly. Codex plugins are surfaced asSkillInfoentries withprovider: "codex-plugin"andproviderLabel: "Codex Plugin ({marketplace})"— no view changes required since all display paths already useproviderLabel. Deduplication is two-tier: byrealPathfirst, then by skill name across Claude and Codex plugin providers.The TOML parser is intentionally minimal (regex-based
[plugins.name]section parsing) to avoid adding a dependency. Highest-version directory wins when multiple versions of a plugin are cached.Changes
src/scanner.tsscanCodexPluginCache(),readCodexMarketplaceFiles(),loadCodexEnabledMap(),parseTomlEnabledMap(); updatescanAllSkills()signature with optionalcodexCacheDir; addCodexPluginManifestimportsrc/utils/types.tscodexPlugin?field toSkillInfo; addCodexPluginManifestinterfacesrc/formatter.tscodex-pluginentry toPROVIDER_COLORS(cyan)src/scanner.test.tsscanCodexPluginCacheandreadCodexMarketplaceFilesTest Results
80 scanner tests pass (up from 55). Pre-existing failures in
publisher.test.tsandcli.test.tsare unrelated to this change (confirmed present onmainbefore this branch).Acceptance Criteria
~/.codex/plugins/cache/) to discover installed Codex pluginsmarketplace.json) from repo-level and user-level.agents/plugins/pathsasm listoutput, distinguished from Claude skills and traditional skills (viaproviderLabel: "Codex Plugin (marketplace-name)")asm info {skill}works for Codex plugins and displays plugin manifest metadata (name, version, description, category viacodexPlugin.category)~/.codex/config.tomlto determine enabled/disabled status of Codex pluginsscanAllSkills)