Skip to content

Commit 478b756

Browse files
committed
fix(plugins): address codex metadata review
Restore Claude skill-array validation, harden marketplace error reporting, and avoid KeyError paths in validation. Refresh Codex marketplace display text and plugin count documentation.
1 parent 8f40842 commit 478b756

3 files changed

Lines changed: 37 additions & 6 deletions

File tree

.agents/plugins/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "duyet-claude-plugins",
33
"interface": {
4-
"displayName": "Duyet Claude Plugins"
4+
"displayName": "Duyet Claude and Codex Plugins"
55
},
66
"plugins": [
77
{

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![GitHub Release](https://img.shields.io/github/v/duyet/claude-plugins?style=flat-square)](https://github.com/duyet/claude-plugins/releases)
44
[![License](https://img.shields.io/github/license/duyet/claude-plugins?style=flat-square)](LICENSE)
5-
[![Plugins](https://img.shields.io/badge/plugins-13-blue?style=flat-square)](#plugins-at-a-glance)
5+
[![Plugins](https://img.shields.io/badge/plugins-14-blue?style=flat-square)](#plugins-at-a-glance)
66

77
> Extend Claude Code and Codex with specialized agents, commands, and skills.
88

scripts/validate-plugins.sh

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,23 @@ elif not isinstance(author, dict):
5151
elif not isinstance(author.get("name"), str) or not author["name"].strip():
5252
errors.append("'author.name' must be a non-empty string")
5353
54+
skills = data.get("skills")
55+
if isinstance(skills, list):
56+
for i, skill in enumerate(skills):
57+
if not isinstance(skill, dict):
58+
errors.append(f"skills[{i}]: must be an object")
59+
continue
60+
if not isinstance(skill.get("name"), str) or not skill["name"].strip():
61+
errors.append(f"skills[{i}]: missing 'name'")
62+
if not isinstance(skill.get("description"), str) or not skill["description"].strip():
63+
errors.append(f"skills[{i}]: missing 'description'")
64+
path_value = skill.get("path")
65+
if path_value is not None:
66+
if not isinstance(path_value, str):
67+
errors.append(f"skills[{i}]: 'path' must be a string")
68+
elif not os.path.isfile(os.path.join(plugin_dir, path_value)):
69+
errors.append(f"skills[{i}]: path '{path_value}' does not exist")
70+
5471
if mode == "codex":
5572
for field in ("skills", "hooks", "mcpServers", "apps"):
5673
value = data.get(field)
@@ -152,23 +169,34 @@ plugin_dirs = sorted(
152169
plugin_set = set(plugin_dirs)
153170
154171
def load_json(relpath):
155-
with open(os.path.join(repo_root, relpath)) as f:
156-
return json.load(f)
172+
try:
173+
with open(os.path.join(repo_root, relpath)) as f:
174+
return json.load(f)
175+
except FileNotFoundError:
176+
errors.append(f"missing {relpath}")
177+
except json.JSONDecodeError as exc:
178+
errors.append(f"{relpath}: invalid JSON: {exc}")
179+
return None
157180
158181
def require(condition, message):
159182
if not condition:
160183
errors.append(message)
161184
162185
root_marketplace = load_json("marketplace.json")
186+
if root_marketplace is None:
187+
root_marketplace = {"plugins": []}
163188
root_names = [plugin.get("name") for plugin in root_marketplace.get("plugins", [])]
164189
require(set(root_names) == plugin_set, "marketplace.json plugin names must match plugin directories")
165190
for plugin in root_marketplace.get("plugins", []):
166191
name = plugin.get("name")
167192
for field in ("name", "id", "description", "version", "type", "category"):
168-
require(isinstance(plugin.get(field), str) and plugin[field].strip(), f"marketplace.json {name}: missing {field}")
193+
value = plugin.get(field)
194+
require(isinstance(value, str) and value.strip(), f"marketplace.json {name}: missing {field}")
169195
require(plugin.get("id") == f"{name}@{root_marketplace.get('name')}", f"marketplace.json {name}: id does not match marketplace name")
170196
171197
claude_marketplace = load_json(".claude-plugin/marketplace.json")
198+
if claude_marketplace is None:
199+
claude_marketplace = {"plugins": []}
172200
claude_names = [plugin.get("name") for plugin in claude_marketplace.get("plugins", [])]
173201
require(set(claude_names).issubset(plugin_set), ".claude-plugin/marketplace.json references unknown plugin")
174202
for plugin in claude_marketplace.get("plugins", []):
@@ -179,6 +207,8 @@ for plugin in claude_marketplace.get("plugins", []):
179207
require(os.path.isdir(os.path.join(repo_root, source)), f".claude-plugin/marketplace.json {name}: source path does not exist")
180208
181209
codex_marketplace = load_json(".agents/plugins/marketplace.json")
210+
if codex_marketplace is None:
211+
codex_marketplace = {"plugins": []}
182212
codex_names = [plugin.get("name") for plugin in codex_marketplace.get("plugins", [])]
183213
require(set(codex_names) == plugin_set, ".agents/plugins/marketplace.json plugin names must match plugin directories")
184214
require(isinstance(codex_marketplace.get("interface", {}).get("displayName"), str), ".agents/plugins/marketplace.json missing interface.displayName")
@@ -197,7 +227,8 @@ for plugin in codex_marketplace.get("plugins", []):
197227
if isinstance(policy, dict):
198228
require(policy.get("installation") in {"NOT_AVAILABLE", "AVAILABLE", "INSTALLED_BY_DEFAULT"}, f".agents/plugins/marketplace.json {name}: invalid policy.installation")
199229
require(policy.get("authentication") in {"ON_INSTALL", "ON_USE"}, f".agents/plugins/marketplace.json {name}: invalid policy.authentication")
200-
require(isinstance(plugin.get("category"), str) and plugin["category"].strip(), f".agents/plugins/marketplace.json {name}: missing category")
230+
category = plugin.get("category")
231+
require(isinstance(category, str) and category.strip(), f".agents/plugins/marketplace.json {name}: missing category")
201232
202233
if errors:
203234
for error in errors:

0 commit comments

Comments
 (0)