Allow empty Superpowers hooks manifest
Publish the completed third-party source refresh after Superpowers 6.1.1 changed its Codex manifest to use an empty no-op hooks object instead of a hooks file path.
Constraint: Current Codex CLI installs superpowers@eapil-skill-market with hooks: {}, while the marketplace validator still rejected empty inline hooks objects.
Rejected: Restore the old hooks directory by hand | Upstream no longer declares those Codex hook files, and hand-restoring generated content would drift from source.
Confidence: high
Scope-risk: moderate
Directive: Empty hooks objects are placeholders; allow them but do not count them as the plugin's only effective component.
Tested: /Users/eapil/git/keyinfo/.venv/bin/python3 scripts/validate_marketplace.py; rg public-secret scan; git diff --check; Codex temp CODEX_HOME marketplace add/list/add superpowers@eapil-skill-market.
Not-tested: Interactive Superpowers skill invocation inside a live Codex thread.
This commit is contained in:
@@ -59,29 +59,46 @@ def validate_hooks_field(plugin_dir: Path, manifest_path: Path, hooks: object) -
|
||||
"""Validate Codex-supported plugin hook declarations.
|
||||
|
||||
Codex supports a hook path string, a list of path strings, an inline hooks
|
||||
object, or a list containing inline hooks objects. The marketplace only
|
||||
verifies path safety and basic type shape; Codex owns hook schema details.
|
||||
object, an empty no-op hooks object, or a list containing hook paths and
|
||||
inline hooks objects. The marketplace only verifies path safety and basic
|
||||
type shape; Codex owns hook schema details.
|
||||
"""
|
||||
|
||||
if isinstance(hooks, str):
|
||||
validate_manifest_path(plugin_dir, manifest_path, hooks, "hooks")
|
||||
return
|
||||
if isinstance(hooks, dict):
|
||||
require(bool(hooks), f"{manifest_path} hooks inline object must not be empty")
|
||||
return
|
||||
if isinstance(hooks, list):
|
||||
require(bool(hooks), f"{manifest_path} hooks list must not be empty")
|
||||
for index, item in enumerate(hooks):
|
||||
if isinstance(item, str):
|
||||
validate_manifest_path(plugin_dir, manifest_path, item, f"hooks[{index}]")
|
||||
elif isinstance(item, dict):
|
||||
require(bool(item), f"{manifest_path} hooks[{index}] inline object must not be empty")
|
||||
continue
|
||||
else:
|
||||
raise AssertionError(f"{manifest_path} hooks[{index}] must be a path or inline object")
|
||||
return
|
||||
raise AssertionError(f"{manifest_path} hooks must be a path, path list, inline object, or inline object list")
|
||||
|
||||
|
||||
def is_declared_component(manifest: dict[str, object], key: str) -> bool:
|
||||
if key not in manifest:
|
||||
return False
|
||||
value = manifest.get(key)
|
||||
if key != "hooks":
|
||||
return True
|
||||
if isinstance(value, str):
|
||||
return bool(value.strip())
|
||||
if isinstance(value, dict):
|
||||
return bool(value)
|
||||
if isinstance(value, list):
|
||||
return any(
|
||||
(isinstance(item, str) and bool(item.strip())) or (isinstance(item, dict) and bool(item))
|
||||
for item in value
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
def validate_skills_component(plugin_dir: Path, manifest_path: Path, skills_rel: object) -> None:
|
||||
require(isinstance(skills_rel, str) and skills_rel.startswith("./"), f"{manifest_path} skills path must be relative ./...")
|
||||
skills_dir = validate_manifest_path(plugin_dir, manifest_path, skills_rel, "skills")
|
||||
@@ -127,11 +144,7 @@ def validate_manifest(plugin_dir: Path, expected_name: str) -> None:
|
||||
author = manifest.get("author")
|
||||
require(isinstance(author, dict) and bool(author.get("name")), f"{manifest_path} missing author.name")
|
||||
|
||||
declared_components = [
|
||||
key
|
||||
for key in ["skills", "mcpServers", "apps", "hooks"]
|
||||
if key in manifest
|
||||
]
|
||||
declared_components = [key for key in ["skills", "mcpServers", "apps", "hooks"] if is_declared_component(manifest, key)]
|
||||
require(bool(declared_components), f"{manifest_path} must declare at least one component: skills, mcpServers, apps, or hooks")
|
||||
|
||||
if "skills" in manifest:
|
||||
|
||||
Reference in New Issue
Block a user