@@ -52,17 +52,19 @@ describe("loader", () => {
5252 sourceDir ?: string ;
5353 hookName : string ;
5454 handlerCode ?: string ;
55+ events ?: string [ ] ;
5556 } ) : Promise < string > {
5657 const sourceDir = params . sourceDir ?? path . join ( tmpDir , "hooks" ) ;
5758 const hookDir = path . join ( sourceDir , params . hookName ) ;
5859 await fs . mkdir ( hookDir , { recursive : true } ) ;
60+ const events = params . events ?? [ "command:new" ] ;
5961 await fs . writeFile (
6062 path . join ( hookDir , "HOOK.md" ) ,
6163 [
6264 "---" ,
6365 `name: ${ params . hookName } ` ,
6466 `description: ${ params . hookName } test hook` ,
65- ' metadata: {"openclaw":{"events":["command:new"]}}' ,
67+ ` metadata: {"openclaw":{"events":${ JSON . stringify ( events ) } }}` ,
6668 "---" ,
6769 "" ,
6870 `# ${ params . hookName } ` ,
@@ -244,6 +246,51 @@ describe("loader", () => {
244246 expect ( event . messages ) . toEqual ( [ "keep-hook" ] ) ;
245247 } ) ;
246248
249+ it ( "registers unknown event keys anyway (advisory warning, not a load failure)" , async ( ) => {
250+ const hooksDir = path . join ( tmpDir , "managed-hooks" ) ;
251+ await writeDiscoveredHook ( {
252+ sourceDir : hooksDir ,
253+ hookName : "typo-hook" ,
254+ events : [ "command:nwe" , "command:new" ] ,
255+ } ) ;
256+
257+ const count = await loadInternalHooks (
258+ {
259+ hooks : {
260+ internal : {
261+ entries : {
262+ "typo-hook" : { enabled : true } ,
263+ } ,
264+ } ,
265+ } ,
266+ } satisfies OpenClawConfig ,
267+ tmpDir ,
268+ { managedHooksDir : hooksDir , bundledHooksDir : "/nonexistent/bundled/hooks" } ,
269+ ) ;
270+
271+ // The typo'd key never fires, but validation is advisory: the hook still
272+ // loads and its valid subscriptions keep working.
273+ expect ( count ) . toBe ( 1 ) ;
274+ const keys = getRegisteredEventKeys ( ) ;
275+ expect ( keys ) . toContain ( "command:nwe" ) ;
276+ expect ( keys ) . toContain ( "command:new" ) ;
277+ const event = createInternalHookEvent ( "command" , "new" , "test-session" ) ;
278+ await triggerInternalHook ( event ) ;
279+ expect ( event . messages ) . toEqual ( [ "typo-hook" ] ) ;
280+ } ) ;
281+
282+ it ( "registers legacy handler events with unknown keys anyway (advisory)" , async ( ) => {
283+ const handlerPath = await writeHandlerModule ( "legacy-typo-handler.js" ) ;
284+
285+ const cfg = createEnabledHooksConfig ( [
286+ { event : "command:nwe" , module : path . basename ( handlerPath ) } ,
287+ ] ) ;
288+
289+ const count = await loadInternalHooks ( cfg , tmpDir ) ;
290+ expect ( count ) . toBe ( 1 ) ;
291+ expect ( getRegisteredEventKeys ( ) ) . toContain ( "command:nwe" ) ;
292+ } ) ;
293+
247294 it ( "should load multiple handlers" , async ( ) => {
248295 // Create test handler modules
249296 const handler1Path = await writeHandlerModule ( "handler1.js" ) ;
0 commit comments