Per-plugin `.codex-plugin/plugin.json` (mirrors the superpowers shape).
(self, plugin: PluginSource)
| 588 | ) |
| 589 | |
| 590 | def _codex_plugin_manifest(self, plugin: PluginSource) -> dict: |
| 591 | """Per-plugin `.codex-plugin/plugin.json` (mirrors the superpowers shape).""" |
| 592 | pj = plugin.plugin_json or {} |
| 593 | manifest: dict = { |
| 594 | "name": plugin.name, |
| 595 | "version": plugin.version, |
| 596 | "description": plugin.description or "", |
| 597 | "skills": "./skills/", |
| 598 | } |
| 599 | if pj.get("author"): |
| 600 | manifest["author"] = pj["author"] |
| 601 | for key in ("homepage", "repository", "license", "keywords"): |
| 602 | if pj.get(key): |
| 603 | manifest[key] = pj[key] |
| 604 | desc = plugin.description or plugin.name |
| 605 | if len(desc) > 120: |
| 606 | # Cut on a word boundary so committed manifests never render mid-word. |
| 607 | desc = desc[:117].rsplit(" ", 1)[0].rstrip(" ,.;:!?-") + "…" |
| 608 | manifest["interface"] = { |
| 609 | "displayName": plugin.name.replace("-", " ").title(), |
| 610 | "shortDescription": desc, |
| 611 | "category": pj.get("category") or "Coding", |
| 612 | } |
| 613 | return manifest |
| 614 | |
| 615 | def _codex_marketplace(self, plugins: list[PluginSource]) -> dict: |
| 616 | """`.agents/plugins/marketplace.json` — entries install the source plugin dirs. |
no outgoing calls
no test coverage detected