Bug Report
File: src/utils/plugins/pluginLoader.ts
Function: finishLoadingPluginFromPath
Lines: ~2913–2919 (current main)
Description
When a plugin has both a plugin.json (with hooks) and a marketplace entry that supplements hooks for the same event, the current code uses an object spread:
// Supplement hooks from marketplace entry
if (entry.hooks) {
plugin.hooksConfig = {
...(plugin.hooksConfig || {}),
...(entry.hooks as HooksSettings), // ← overwrites same-event arrays
}
}
HooksSettings values are arrays of matchers keyed by event name (e.g. PreToolUse, PostToolUse). The spread replaces the entire event array from plugin.json with the marketplace entry's array, silently dropping any matchers already registered by the plugin manifest.
Root cause
mergeHooksSettings() already exists in the same file (line ~1861) and concatenates per-event arrays correctly:
merged[event] = [...(merged[event] || []), ...matchers]
It is used correctly in createPluginFromPath (lines ~1722, ~1759) but was not applied in the marketplace supplement path in finishLoadingPluginFromPath.
Reproduction (mental model)
- Plugin
foo has plugin.json declaring PreToolUse: [matcherA]
- Marketplace entry for
foo supplements with hooks: { PreToolUse: [matcherB] }
- Expected:
hooksConfig.PreToolUse = [matcherA, matcherB]
- Actual:
hooksConfig.PreToolUse = [matcherB] ← matcherA lost
Fix
Replace the spread with the existing mergeHooksSettings():
// Supplement hooks from marketplace entry
if (entry.hooks) {
plugin.hooksConfig = mergeHooksSettings(
plugin.hooksConfig,
entry.hooks as HooksSettings,
)
}
A PR with this fix is available: https://github.com/rodrigoeqnit/openclaude/compare/fix/pluginloader-hooks-merge
Severity
Medium — hooks from plugin.json are silently dropped in the marketplace supplement path. The regression is invisible (no error, no warning), making it hard to debug.
Bug Report
File:
src/utils/plugins/pluginLoader.tsFunction:
finishLoadingPluginFromPathLines: ~2913–2919 (current
main)Description
When a plugin has both a
plugin.json(with hooks) and a marketplace entry that supplements hooks for the same event, the current code uses an object spread:HooksSettingsvalues are arrays of matchers keyed by event name (e.g.PreToolUse,PostToolUse). The spread replaces the entire event array fromplugin.jsonwith the marketplace entry's array, silently dropping any matchers already registered by the plugin manifest.Root cause
mergeHooksSettings()already exists in the same file (line ~1861) and concatenates per-event arrays correctly:It is used correctly in
createPluginFromPath(lines ~1722, ~1759) but was not applied in the marketplace supplement path infinishLoadingPluginFromPath.Reproduction (mental model)
foohasplugin.jsondeclaringPreToolUse: [matcherA]foosupplements withhooks: { PreToolUse: [matcherB] }hooksConfig.PreToolUse = [matcherA, matcherB]hooksConfig.PreToolUse = [matcherB]← matcherA lostFix
Replace the spread with the existing
mergeHooksSettings():A PR with this fix is available: https://github.com/rodrigoeqnit/openclaude/compare/fix/pluginloader-hooks-merge
Severity
Medium — hooks from
plugin.jsonare silently dropped in the marketplace supplement path. The regression is invisible (no error, no warning), making it hard to debug.