diff --git a/app/plugins/builtins/calendar/routes.py b/app/plugins/builtins/calendar/routes.py index d62f62a..0a78034 100644 --- a/app/plugins/builtins/calendar/routes.py +++ b/app/plugins/builtins/calendar/routes.py @@ -471,6 +471,7 @@ async def create_entry( # ── Hook: calendar.after_appointment (Action) ── from app.core.hooks import do_action await do_action("calendar.after_appointment", entry_id=str(entry.id), tenant_id=tenant_id, user_id=user_id) + await do_action("calendar_entry.after_create", entry_id=str(entry.id), tenant_id=tenant_id, user_id=user_id) # Schedule reminder ARQ job if reminder is set if body.reminder: @@ -665,6 +666,7 @@ async def update_entry( snapshot_before=snapshot_before, snapshot_after=snapshot_after, changes=changes or None) from app.core.hooks import do_action await do_action("calendar.after_update", entry_id=str(entry.id), tenant_id=tenant_id, user_id=user_id) + await do_action("calendar_entry.after_update", entry_id=str(entry.id), tenant_id=tenant_id, user_id=user_id) return snapshot_after @@ -694,6 +696,7 @@ async def delete_entry( await record_history(db, tenant_id, user_id, "calendar_entry", entry.id, "delete", snapshot_before=snapshot_before) from app.core.hooks import do_action await do_action("calendar.after_delete", tenant_id=tenant_id, user_id=user_id, entry_id=entry_id) + await do_action("calendar_entry.after_delete", tenant_id=tenant_id, user_id=user_id, entry_id=entry_id) return Response(status_code=204) diff --git a/app/plugins/builtins/dms/routes.py b/app/plugins/builtins/dms/routes.py index 70b141f..6432afe 100644 --- a/app/plugins/builtins/dms/routes.py +++ b/app/plugins/builtins/dms/routes.py @@ -623,6 +623,7 @@ async def upload_file( # Lifecycle hook: dms.after_upload from app.core.hooks import do_action await do_action("dms.after_upload", {'id': str(dms_file.id), 'name': dms_file.name, 'folder_id': str(dms_file.folder_id) if dms_file.folder_id else None, 'mime_type': dms_file.mime_type, 'size_bytes': dms_file.size_bytes}, db=db, tenant_id=tenant_id, user_id=user_id) + await do_action("dms_file.after_create", {'id': str(dms_file.id), 'name': dms_file.name, 'tenant_id': str(tenant_id)}, db=db, tenant_id=tenant_id, user_id=user_id) # Outbox event: file.created from app.core.outbox import enqueue_outbox_event @@ -846,6 +847,7 @@ async def update_file( # Lifecycle hook: dms.after_update from app.core.hooks import do_action await do_action("dms.after_update", {'id': str(dms_file.id), 'name': dms_file.name}, db=db, tenant_id=tenant_id, user_id=user_id, file_id=file_id) + await do_action("dms_file.after_update", {'id': str(dms_file.id), 'name': dms_file.name, 'tenant_id': str(tenant_id)}, db=db, tenant_id=tenant_id, user_id=user_id, file_id=file_id) return { "id": str(dms_file.id), @@ -908,6 +910,7 @@ async def delete_file( # Lifecycle hook: dms.after_delete await do_action("dms.after_delete", db=db, tenant_id=tenant_id, user_id=user_id, file_id=file_id) + await do_action("dms_file.after_delete", db=db, tenant_id=tenant_id, user_id=user_id, file_id=file_id) # Outbox event: file.deleted from app.core.outbox import enqueue_outbox_event diff --git a/app/plugins/builtins/mail/services.py b/app/plugins/builtins/mail/services.py index a4494e9..0cacf1c 100644 --- a/app/plugins/builtins/mail/services.py +++ b/app/plugins/builtins/mail/services.py @@ -826,6 +826,7 @@ async def imap_sync_folder( # Lifecycle hook: mail.after_receive from app.core.hooks import do_action await do_action("mail.after_receive", {'mail_id': str(mail.id), 'tenant_id': str(tenant_id), 'account_id': str(account.id), 'folder_id': str(folder.id), 'subject': subject, 'from_address': from_addr}, db=db, tenant_id=tenant_id) + await do_action("mail.after_create", {'mail_id': str(mail.id), 'tenant_id': str(tenant_id), 'subject': subject, 'from_address': from_addr}, db=db, tenant_id=tenant_id) # Outbox event: mail.received from app.core.outbox import enqueue_outbox_event @@ -1584,6 +1585,7 @@ async def send_mail_via_smtp( # ── Hook: mail.after_send (Action) ── from app.core.hooks import do_action await do_action("mail.after_send", mail_data, db=db, account=account, msg_id=msg_id) + await do_action("mail.after_update", mail_data, db=db, tenant_id=str(mail_data.get('tenant_id', '')) if isinstance(mail_data, dict) else None) # Store sent mail in Sent folder — use configured mapping if set, # otherwise flexible lookup to handle different IMAP naming conventions diff --git a/app/services/contact_service.py b/app/services/contact_service.py index d5b3b80..bc7fdad 100644 --- a/app/services/contact_service.py +++ b/app/services/contact_service.py @@ -464,6 +464,9 @@ async def delete_contact( action="delete", snapshot_before=snapshot_before, ) + # Hook: contact.after_delete + await do_action("contact.after_delete", db=db, tenant_id=tenant_id, contact_id=contact_id, user_id=user_id) + async def hard_delete_contact(db: AsyncSession, tenant_id: uuid.UUID, contact_id: str) -> None: """GDPR hard-delete a contact.""" diff --git a/scripts/test_suite/marathon_results.json b/scripts/test_suite/marathon_results.json index 141a41a..5e7bac6 100644 --- a/scripts/test_suite/marathon_results.json +++ b/scripts/test_suite/marathon_results.json @@ -1,8 +1,8 @@ { - "timestamp": "2026-08-17T07:15:04.567567", - "total_time": 5.77, + "timestamp": "2026-08-17T07:17:53.788386", + "total_time": 6.71, "total_scripts": 7, - "total_issues": 1110, + "total_issues": 1109, "passed": 1, "failed": 6, "skipped": 0, @@ -12,7 +12,7 @@ "description": "Frontend\u2194Backend API Contracts", "status": "FAIL", "exit_code": 246, - "elapsed": 0.29, + "elapsed": 0.31, "issues": 758 }, { @@ -20,7 +20,7 @@ "description": "Hook Registrations vs Triggers", "status": "FAIL", "exit_code": 1, - "elapsed": 0.11, + "elapsed": 0.05, "issues": 0 }, { @@ -28,7 +28,7 @@ "description": "Dead Functions (defined but never called)", "status": "FAIL", "exit_code": 3, - "elapsed": 2.47, + "elapsed": 2.6, "issues": 3 }, { @@ -36,7 +36,7 @@ "description": "Unused Store Actions/State", "status": "FAIL", "exit_code": 67, - "elapsed": 0.07, + "elapsed": 0.12, "issues": 323 }, { @@ -44,7 +44,7 @@ "description": "Contract Attribute Mismatches", "status": "PASS", "exit_code": 0, - "elapsed": 1.42, + "elapsed": 2.01, "issues": 0 }, { @@ -52,16 +52,16 @@ "description": "Plugin\u2192Manifest\u2192Frontend Verkabelung", "status": "FAIL", "exit_code": 24, - "elapsed": 0.12, + "elapsed": 0.14, "issues": 24 }, { "name": "trace_imports", "description": "Broken/Missing Imports", "status": "FAIL", - "exit_code": 2, - "elapsed": 1.28, - "issues": 2 + "exit_code": 1, + "elapsed": 1.49, + "issues": 1 } ] } \ No newline at end of file diff --git a/scripts/test_suite/results_trace_functions.json b/scripts/test_suite/results_trace_functions.json index c9c9a18..062f314 100644 --- a/scripts/test_suite/results_trace_functions.json +++ b/scripts/test_suite/results_trace_functions.json @@ -1,6 +1,6 @@ { "py_defs": 1616, - "py_dead": 628, + "py_dead": 629, "ts_defs": 959, "ts_dead": 442, "critical_dead": [ diff --git a/scripts/test_suite/results_trace_hooks.json b/scripts/test_suite/results_trace_hooks.json new file mode 100644 index 0000000..2b818dc --- /dev/null +++ b/scripts/test_suite/results_trace_hooks.json @@ -0,0 +1,670 @@ +{ + "registrations": [ + { + "file": "app/core/hooks.py", + "hook_name": "contact.before_create" + }, + { + "file": "app/core/hooks.py", + "hook_name": "contact.format_display_name" + }, + { + "file": "app/plugins/builtins/dms/plugin.py", + "hook_name": "dms_file.after_create" + }, + { + "file": "app/plugins/builtins/dms/plugin.py", + "hook_name": "dms_file.after_update" + }, + { + "file": "app/plugins/builtins/dms/plugin.py", + "hook_name": "dms_file.after_delete" + }, + { + "file": "app/plugins/builtins/mail/plugin.py", + "hook_name": "mail.after_create" + }, + { + "file": "app/plugins/builtins/mail/plugin.py", + "hook_name": "mail.after_update" + }, + { + "file": "app/plugins/builtins/mail/plugin.py", + "hook_name": "mail.after_delete" + }, + { + "file": "app/plugins/builtins/contacts/plugin.py", + "hook_name": "contact.after_create" + }, + { + "file": "app/plugins/builtins/contacts/plugin.py", + "hook_name": "contact.after_update" + }, + { + "file": "app/plugins/builtins/contacts/plugin.py", + "hook_name": "contact.after_delete" + }, + { + "file": "app/plugins/builtins/tasks/plugin.py", + "hook_name": "task.after_create" + }, + { + "file": "app/plugins/builtins/tasks/plugin.py", + "hook_name": "task.after_update" + }, + { + "file": "app/plugins/builtins/tasks/plugin.py", + "hook_name": "task.after_delete" + }, + { + "file": "app/plugins/builtins/calendar/plugin.py", + "hook_name": "calendar_entry.after_create" + }, + { + "file": "app/plugins/builtins/calendar/plugin.py", + "hook_name": "calendar_entry.after_update" + }, + { + "file": "app/plugins/builtins/calendar/plugin.py", + "hook_name": "calendar_entry.after_delete" + } + ], + "triggers": [ + { + "file": "app/routes/companies.py", + "hook_name": "company.before_create" + }, + { + "file": "app/routes/companies.py", + "hook_name": "company.after_create" + }, + { + "file": "app/routes/companies.py", + "hook_name": "company.before_update" + }, + { + "file": "app/routes/companies.py", + "hook_name": "company.after_update" + }, + { + "file": "app/routes/companies.py", + "hook_name": "company.before_delete" + }, + { + "file": "app/routes/companies.py", + "hook_name": "company.after_delete" + }, + { + "file": "app/services/contact_service.py", + "hook_name": "contact.before_create" + }, + { + "file": "app/services/contact_service.py", + "hook_name": "contact.after_create" + }, + { + "file": "app/services/contact_service.py", + "hook_name": "contact.before_update" + }, + { + "file": "app/services/contact_service.py", + "hook_name": "contact.after_update" + }, + { + "file": "app/services/contact_service.py", + "hook_name": "contact.before_delete" + }, + { + "file": "app/services/contact_service.py", + "hook_name": "contact.format_display_name" + }, + { + "file": "app/services/auth_service.py", + "hook_name": "auth.after_login" + }, + { + "file": "app/services/auth_service.py", + "hook_name": "auth.before_login" + }, + { + "file": "app/services/workflow_service.py", + "hook_name": "workflow.before_start" + }, + { + "file": "app/services/workflow_service.py", + "hook_name": "workflow.after_start" + }, + { + "file": "app/services/workflow_service.py", + "hook_name": "workflow.after_complete" + }, + { + "file": "app/services/workflow_service.py", + "hook_name": "workflow.after_cancel" + }, + { + "file": "app/services/user_service.py", + "hook_name": "user.before_create" + }, + { + "file": "app/services/user_service.py", + "hook_name": "user.after_create" + }, + { + "file": "app/core/hooks.py", + "hook_name": "contact.before_create" + }, + { + "file": "app/core/hooks.py", + "hook_name": "contact.before_create" + }, + { + "file": "app/core/hooks.py", + "hook_name": "contact.format_display_name" + }, + { + "file": "app/core/hooks.py", + "hook_name": "contact.format_name" + }, + { + "file": "app/plugins/builtins/automation/agent_runner.py", + "hook_name": "agent.before_run" + }, + { + "file": "app/plugins/builtins/automation/agent_runner.py", + "hook_name": "agent.after_run" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.folder.before_create" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.folder.after_create" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.folder.before_delete" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.folder.after_delete" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.after_upload" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.before_update" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.after_update" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.before_delete" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.after_delete" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.before_restore" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.after_restore" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.before_upload" + }, + { + "file": "app/plugins/builtins/mail/services.py", + "hook_name": "mail.after_receive" + }, + { + "file": "app/plugins/builtins/mail/services.py", + "hook_name": "mail.after_send" + }, + { + "file": "app/plugins/builtins/mail/services.py", + "hook_name": "mail.before_delete" + }, + { + "file": "app/plugins/builtins/mail/services.py", + "hook_name": "mail.after_delete" + }, + { + "file": "app/plugins/builtins/mail/services.py", + "hook_name": "mail.before_move" + }, + { + "file": "app/plugins/builtins/mail/services.py", + "hook_name": "mail.after_move" + }, + { + "file": "app/plugins/builtins/mail/services.py", + "hook_name": "mail.before_send" + }, + { + "file": "app/plugins/builtins/tasks/services.py", + "hook_name": "task.before_create" + }, + { + "file": "app/plugins/builtins/tasks/services.py", + "hook_name": "task.after_create" + }, + { + "file": "app/plugins/builtins/tasks/services.py", + "hook_name": "task.before_update" + }, + { + "file": "app/plugins/builtins/tasks/services.py", + "hook_name": "task.after_update" + }, + { + "file": "app/plugins/builtins/tasks/services.py", + "hook_name": "task.before_delete" + }, + { + "file": "app/plugins/builtins/tasks/services.py", + "hook_name": "task.after_delete" + }, + { + "file": "app/plugins/builtins/calendar/routes.py", + "hook_name": "calendar.before_appointment" + }, + { + "file": "app/plugins/builtins/calendar/routes.py", + "hook_name": "calendar.after_appointment" + }, + { + "file": "app/plugins/builtins/calendar/routes.py", + "hook_name": "calendar.before_update" + }, + { + "file": "app/plugins/builtins/calendar/routes.py", + "hook_name": "calendar.after_update" + }, + { + "file": "app/plugins/builtins/calendar/routes.py", + "hook_name": "calendar.before_delete" + }, + { + "file": "app/plugins/builtins/calendar/routes.py", + "hook_name": "calendar.after_delete" + }, + { + "file": "app/plugins/builtins/unified_search/search_engine.py", + "hook_name": "search.before_search" + }, + { + "file": "app/plugins/builtins/unified_search/search_engine.py", + "hook_name": "search.after_search" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.conversation.before_create" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.conversation.after_create" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.before_message" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.after_message" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.before_edit" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.after_edit" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.before_delete" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.after_delete" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.before_create" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.after_create" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.before_assign" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.after_assign" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.before_unassign" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.after_unassign" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.before_delete" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.after_delete" + } + ], + "orphan_registrations": [ + { + "file": "app/plugins/builtins/dms/plugin.py", + "hook_name": "dms_file.after_create" + }, + { + "file": "app/plugins/builtins/dms/plugin.py", + "hook_name": "dms_file.after_update" + }, + { + "file": "app/plugins/builtins/dms/plugin.py", + "hook_name": "dms_file.after_delete" + }, + { + "file": "app/plugins/builtins/mail/plugin.py", + "hook_name": "mail.after_create" + }, + { + "file": "app/plugins/builtins/mail/plugin.py", + "hook_name": "mail.after_update" + }, + { + "file": "app/plugins/builtins/contacts/plugin.py", + "hook_name": "contact.after_delete" + }, + { + "file": "app/plugins/builtins/calendar/plugin.py", + "hook_name": "calendar_entry.after_create" + }, + { + "file": "app/plugins/builtins/calendar/plugin.py", + "hook_name": "calendar_entry.after_update" + }, + { + "file": "app/plugins/builtins/calendar/plugin.py", + "hook_name": "calendar_entry.after_delete" + } + ], + "orphan_triggers": [ + { + "file": "app/routes/companies.py", + "hook_name": "company.before_create" + }, + { + "file": "app/routes/companies.py", + "hook_name": "company.after_create" + }, + { + "file": "app/routes/companies.py", + "hook_name": "company.before_update" + }, + { + "file": "app/routes/companies.py", + "hook_name": "company.after_update" + }, + { + "file": "app/routes/companies.py", + "hook_name": "company.before_delete" + }, + { + "file": "app/routes/companies.py", + "hook_name": "company.after_delete" + }, + { + "file": "app/services/contact_service.py", + "hook_name": "contact.before_update" + }, + { + "file": "app/services/contact_service.py", + "hook_name": "contact.before_delete" + }, + { + "file": "app/services/auth_service.py", + "hook_name": "auth.after_login" + }, + { + "file": "app/services/auth_service.py", + "hook_name": "auth.before_login" + }, + { + "file": "app/services/workflow_service.py", + "hook_name": "workflow.before_start" + }, + { + "file": "app/services/workflow_service.py", + "hook_name": "workflow.after_start" + }, + { + "file": "app/services/workflow_service.py", + "hook_name": "workflow.after_complete" + }, + { + "file": "app/services/workflow_service.py", + "hook_name": "workflow.after_cancel" + }, + { + "file": "app/services/user_service.py", + "hook_name": "user.before_create" + }, + { + "file": "app/services/user_service.py", + "hook_name": "user.after_create" + }, + { + "file": "app/core/hooks.py", + "hook_name": "contact.format_name" + }, + { + "file": "app/plugins/builtins/automation/agent_runner.py", + "hook_name": "agent.before_run" + }, + { + "file": "app/plugins/builtins/automation/agent_runner.py", + "hook_name": "agent.after_run" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.folder.before_create" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.folder.after_create" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.folder.before_delete" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.folder.after_delete" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.after_upload" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.before_update" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.after_update" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.before_delete" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.after_delete" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.before_restore" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.after_restore" + }, + { + "file": "app/plugins/builtins/dms/routes.py", + "hook_name": "dms.before_upload" + }, + { + "file": "app/plugins/builtins/mail/services.py", + "hook_name": "mail.after_receive" + }, + { + "file": "app/plugins/builtins/mail/services.py", + "hook_name": "mail.after_send" + }, + { + "file": "app/plugins/builtins/mail/services.py", + "hook_name": "mail.before_delete" + }, + { + "file": "app/plugins/builtins/mail/services.py", + "hook_name": "mail.before_move" + }, + { + "file": "app/plugins/builtins/mail/services.py", + "hook_name": "mail.after_move" + }, + { + "file": "app/plugins/builtins/mail/services.py", + "hook_name": "mail.before_send" + }, + { + "file": "app/plugins/builtins/tasks/services.py", + "hook_name": "task.before_create" + }, + { + "file": "app/plugins/builtins/tasks/services.py", + "hook_name": "task.before_update" + }, + { + "file": "app/plugins/builtins/tasks/services.py", + "hook_name": "task.before_delete" + }, + { + "file": "app/plugins/builtins/calendar/routes.py", + "hook_name": "calendar.before_appointment" + }, + { + "file": "app/plugins/builtins/calendar/routes.py", + "hook_name": "calendar.after_appointment" + }, + { + "file": "app/plugins/builtins/calendar/routes.py", + "hook_name": "calendar.before_update" + }, + { + "file": "app/plugins/builtins/calendar/routes.py", + "hook_name": "calendar.after_update" + }, + { + "file": "app/plugins/builtins/calendar/routes.py", + "hook_name": "calendar.before_delete" + }, + { + "file": "app/plugins/builtins/calendar/routes.py", + "hook_name": "calendar.after_delete" + }, + { + "file": "app/plugins/builtins/unified_search/search_engine.py", + "hook_name": "search.before_search" + }, + { + "file": "app/plugins/builtins/unified_search/search_engine.py", + "hook_name": "search.after_search" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.conversation.before_create" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.conversation.after_create" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.before_message" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.after_message" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.before_edit" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.after_edit" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.before_delete" + }, + { + "file": "app/plugins/builtins/kommunikation/services.py", + "hook_name": "comm.after_delete" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.before_create" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.after_create" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.before_assign" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.after_assign" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.before_unassign" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.after_unassign" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.before_delete" + }, + { + "file": "app/plugins/builtins/tags/routes.py", + "hook_name": "tag.after_delete" + } + ] +} \ No newline at end of file diff --git a/scripts/test_suite/results_trace_imports.json b/scripts/test_suite/results_trace_imports.json index d3ffeb7..2e350e5 100644 --- a/scripts/test_suite/results_trace_imports.json +++ b/scripts/test_suite/results_trace_imports.json @@ -7,13 +7,6 @@ "name": "SessionModel", "line": 261, "issue": "Name 'SessionModel' not found in module" - }, - { - "file": "app/plugins/builtins/automation/agent_runner.py", - "module": "app.services.mail_service", - "name": "MailService", - "line": 115, - "issue": "Module not found" } ] } \ No newline at end of file diff --git a/scripts/test_suite/results_trace_stores.json b/scripts/test_suite/results_trace_stores.json index 626502e..73e2a11 100644 --- a/scripts/test_suite/results_trace_stores.json +++ b/scripts/test_suite/results_trace_stores.json @@ -1,701 +1,701 @@ { "stores": { "calendarStore": [ - "setViewMode", - "setVisibleMonth", - "setRangeEnd", - "visibleMonth", - "rangeStart", - "date", - "goToPrevWeek", - "goToToday", - "goToNextWeek", - "rangeEnd", - "setVisibleWeek", - "selectedEntry", - "setVisibleDay", - "calendars", - "goToPrevDay", "visibleCalendarIds", "entry", - "setRangeStart", - "goToNextDay", - "setCalendars", - "toggleCalendarVisibility", - "goToPrevMonth", - "setActiveCalendarId", - "visibleWeek", - "visibleDay", - "setSelectedEntry", - "mode", "goToNextMonth", + "setVisibleWeek", + "rangeStart", + "setViewMode", + "setVisibleDay", + "visibleDay", + "setVisibleMonth", + "goToNextWeek", + "goToNextDay", + "goToToday", + "setRangeStart", + "date", "activeCalendarId", - "viewMode" + "visibleMonth", + "goToPrevWeek", + "toggleCalendarVisibility", + "setActiveCalendarId", + "goToPrevMonth", + "setRangeEnd", + "viewMode", + "calendars", + "setCalendars", + "selectedEntry", + "rangeEnd", + "goToPrevDay", + "mode", + "visibleWeek", + "setSelectedEntry" ], "aiUIControlStore": [ - "setAIActive", - "clearPending", - "status", - "commandHistory", - "setLastFeedback", - "active", - "setConnected", - "settings", - "value", - "entity", - "addCommandToHistory", - "lastFeedback", - "connected", - "activeTab", "action", - "aiActive", - "setPendingFilter", - "section", - "setPendingSettings", - "pendingSettings", - "feedback", - "setActiveTab", + "active", + "status", + "setAIActive", "setActiveCommand", - "command_id", - "modal", - "pendingFilter", - "filter", + "setPendingSettings", "activeModal", + "setActiveTab", "setActiveModal", - "activeCommand" + "filter", + "feedback", + "activeCommand", + "modal", + "activeTab", + "aiActive", + "lastFeedback", + "addCommandToHistory", + "settings", + "connected", + "pendingSettings", + "setConnected", + "command_id", + "pendingFilter", + "commandHistory", + "value", + "setLastFeedback", + "section", + "setPendingFilter", + "clearPending", + "entity" ], "onboardingStore": [ - "isActive", - "reset", - "step", - "complete", - "start", - "next", - "goToStep", "prev", "skipped", - "completed", + "next", + "complete", "skip", - "data" + "start", + "data", + "reset", + "step", + "isActive", + "completed", + "goToStep" ], "windowStore": [ - "activeWindowId", - "type", - "const", - "updateWindowSize", - "toggleAiChat", - "updateWindowPosition", "component", - "nextZIndex", - "height", "restoreWindow", - "openWindow", - "closeWindow", - "newWindow", - "windows", - "null", - "setActiveWindow", - "aiChatVisible", - "componentProps", - "size", - "zIndex", - "config", "toggleFullscreen", - "position", - "title", + "setActiveWindow", + "height", + "updateWindowPosition", "minimizeWindow", - "width" + "openWindow", + "componentProps", + "closeWindow", + "config", + "windows", + "toggleAiChat", + "position", + "null", + "title", + "width", + "const", + "size", + "type", + "aiChatVisible", + "nextZIndex", + "zIndex", + "activeWindowId", + "updateWindowSize", + "newWindow" ], "commandPaletteStore": [ - "isOpen", - "toggle", + "open", "close", - "open" + "isOpen", + "toggle" ], "pluginToolbarStore": [ - "null", - "items", - "setActivePlugin", - "query", - "updates", - "onClick", - "unregisterPlugin", - "label", "value", - "activePlugin", "updateItem", + "updates", + "items", + "registerItems", + "setActivePlugin", + "onClick", + "label", "plugin", - "registerItems" + "activePlugin", + "null", + "query", + "unregisterPlugin" ], "commStore": [ - "sender_type", - "file_name", - "blocks", - "convId", - "loading", - "setLoading", - "block_type", - "unreadCounts", - "is_archived", - "setTyping", - "messages", - "file_id", - "setMessages", - "is_pinned", - "display_name", - "file_size", - "sender_id", - "setActiveConversation", - "updateConversation", - "setUnread", + "participant_type", + "thumbnail_path", "convs", "participant_id", + "block_type", + "blocks", + "updateConversation", + "file_id", "locked_by", - "created_by_type", - "last_msg_sender_type", - "block_data", - "is_direct", - "thumbnail_path", - "attachments", - "content", - "created_at", - "userIds", - "count", - "reactions", - "activeConversationId", - "participant_type", - "conv", - "content_format", - "edited_at", - "unread_count", - "created_by", - "participants", - "last_msg_preview", - "reply_to_id", - "file_source", - "sort_order", - "conversations", - "conversation_id", - "metadata", - "typingUsers", - "msgs", - "role", + "messages", "last_msg_at", - "setConversations", - "addMessage", + "display_name", + "content_format", + "activeConversationId", + "setActiveConversation", + "is_direct", + "typingUsers", + "count", + "loading", + "convId", + "last_msg_preview", + "file_source", + "role", + "is_archived", + "participants", + "setLoading", "title", + "setConversations", + "sender_type", + "addMessage", + "unread_count", + "is_locked", + "userIds", + "sender_id", + "created_by_type", + "content", + "edited_at", + "setMessages", + "block_data", + "reply_to_id", + "conversations", + "msgs", + "conversation_id", "file_type", - "is_locked" + "unreadCounts", + "metadata", + "sort_order", + "conv", + "file_size", + "created_at", + "attachments", + "file_name", + "setTyping", + "setUnread", + "reactions", + "last_msg_sender_type", + "is_pinned", + "created_by" ], "pluginStore": [ - "getAllPageRoutes", - "path", + "is_core", + "entity_type", + "component", + "detail_tabs", + "loaded", + "display_name", + "label_key", + "setManifests", + "entityType", + "getAllSettingsPages", + "group", "options", + "version", + "permission", "loading", - "default_value", - "reset", + "menu_items", + "manifests", + "getAllDashboardWidgets", "setLoading", "protected", - "icon", - "required", - "display_name", - "component", - "group", - "entityType", - "getAllDashboardWidgets", - "label", - "entity", - "manifests", - "col_span", - "order", - "getDetailTabsForEntity", - "menu_items", - "getAllMenuItems", "parent", - "settings_pages", - "entity_type", - "is_core", + "default_value", + "path", + "order", + "label", + "page_routes", + "row_span", + "getAllMenuItems", + "badge_key", + "col_span", + "icon", + "getCustomFieldsForEntity", + "error", + "getAllPageRoutes", + "field_type", + "reset", + "getDetailTabsForEntity", "custom_fields", "dashboard_widgets", - "detail_tabs", - "version", - "badge_key", - "row_span", - "permission", - "setManifests", - "error", - "label_key", - "loaded", - "field_type", - "getAllSettingsPages", - "page_routes", + "required", "setError", - "getCustomFieldsForEntity" + "settings_pages", + "entity" ], "themeStore": [ - "config", - "applyTheme", - "target", - "toggleDarkMode", - "borderRadius", - "DEFAULT_THEME", - "amount", + "setTheme", "loadFromStorage", + "DEFAULT_THEME", + "scales", "saveToStorage", "primaryColor", - "base", - "scales", + "config", + "amount", + "target", "result", - "fontFamily", "darkMode", - "setTheme", - "accentColor" + "toggleDarkMode", + "fontFamily", + "applyTheme", + "borderRadius", + "accentColor", + "base" ], "uiStore": [ - "suggestionSidebarOpen", + "toggleSidebar", + "collapsed", + "setAISidebarCollapsed", + "setLocale", + "toggleAISidebar", + "toast", + "setAISidebarTab", + "addToast", + "setMessageSidebarCollapsed", + "open", + "sidebarOpen", + "messageSidebarCollapsed", "message", + "setTheme", + "openAISidebarProactive", + "toggleSuggestionSidebar", + "toasts", + "toggleMessageSidebar", + "clearNotifications", "type", "notifications", - "clearNotifications", - "toasts", - "addToast", - "open", - "aiSidebarCollapsed", - "removeNotification", - "collapsed", - "aiSidebarTab", - "locale", "setSidebarOpen", - "theme", - "setAISidebarTab", - "toggleMessageSidebar", - "toggleSidebar", - "toggleSuggestionSidebar", - "toast", - "setAISidebarCollapsed", - "index", - "toggleAISidebar", - "setLocale", - "openAISidebarProactive", - "setTheme", - "messageSidebarCollapsed", - "sidebarOpen", + "aiSidebarTab", "clearToasts", + "locale", + "index", + "removeNotification", "removeToast", - "setMessageSidebarCollapsed" + "aiSidebarCollapsed", + "suggestionSidebarOpen", + "theme" ], "workspaceStore": [ - "visibleModuleKeys", - "reset", - "loading", - "setLoading", - "icon", - "is_default", - "setActiveWorkspace", - "isModuleVisible", - "moduleKey", - "modules", - "module_key", - "is_active", - "setContext", - "context", - "height", - "isLoading", - "hasWorkspaces", - "workspaces", - "menu_order", - "setMyWorkspaces", - "description", - "activeWorkspaceId", - "myWorkspaces", - "workspace_id", - "config", - "is_visible", "widgets", - "widget_key", + "visibleModuleKeys", + "is_active", + "activeWorkspaceId", + "moduleKey", "position_y", + "height", + "description", + "is_visible", + "module_key", "position_x", - "width" + "loading", + "menu_order", + "setContext", + "config", + "setLoading", + "isModuleVisible", + "setMyWorkspaces", + "width", + "context", + "myWorkspaces", + "widget_key", + "workspaces", + "is_default", + "workspace_id", + "icon", + "hasWorkspaces", + "reset", + "isLoading", + "setActiveWorkspace", + "modules" ], "authStore": [ + "setUser", + "last_name", + "first_name", + "setAuthenticated", + "setTenant", "loading", + "field_permissions", + "authed", + "role", + "currentTenant", "setLoading", - "user", - "avatar_url", + "slug", + "isAuthenticated", + "fieldPerms", + "tenants", "logout", "is_system_admin", - "slug", - "setAuthenticated", - "isLoading", - "perms", - "permissions", - "setPermissions", - "setUser", - "tenants", - "email", - "setTenant", - "authed", - "first_name", - "isSystemAdmin", + "user", "tenant", - "fieldPerms", + "setPermissions", + "permissions", "error", - "role", - "field_permissions", - "isAuthenticated", - "last_name", + "perms", + "email", + "avatar_url", + "isLoading", "setError", - "currentTenant" + "isSystemAdmin" ] }, "usage": {}, "unused": { "calendarStore": [ - "setViewMode", - "setVisibleMonth", - "setRangeEnd", - "visibleMonth", - "rangeStart", - "date", - "goToPrevWeek", - "goToToday", - "goToNextWeek", - "rangeEnd", - "setVisibleWeek", - "selectedEntry", - "setVisibleDay", - "calendars", - "goToPrevDay", "visibleCalendarIds", "entry", - "setRangeStart", - "goToNextDay", - "setCalendars", - "toggleCalendarVisibility", - "goToPrevMonth", - "setActiveCalendarId", - "visibleWeek", - "visibleDay", - "setSelectedEntry", - "mode", "goToNextMonth", + "setVisibleWeek", + "rangeStart", + "setViewMode", + "setVisibleDay", + "visibleDay", + "setVisibleMonth", + "goToNextWeek", + "goToNextDay", + "goToToday", + "setRangeStart", + "date", "activeCalendarId", - "viewMode" + "visibleMonth", + "goToPrevWeek", + "toggleCalendarVisibility", + "setActiveCalendarId", + "goToPrevMonth", + "setRangeEnd", + "viewMode", + "calendars", + "setCalendars", + "selectedEntry", + "rangeEnd", + "goToPrevDay", + "mode", + "visibleWeek", + "setSelectedEntry" ], "aiUIControlStore": [ - "setAIActive", - "clearPending", - "status", - "commandHistory", - "setLastFeedback", - "active", - "setConnected", - "settings", - "value", - "entity", - "addCommandToHistory", - "lastFeedback", - "connected", - "activeTab", "action", - "aiActive", - "setPendingFilter", - "section", - "setPendingSettings", - "pendingSettings", - "feedback", - "setActiveTab", + "active", + "status", + "setAIActive", "setActiveCommand", - "command_id", - "modal", - "pendingFilter", - "filter", + "setPendingSettings", "activeModal", + "setActiveTab", "setActiveModal", - "activeCommand" + "filter", + "feedback", + "activeCommand", + "modal", + "activeTab", + "aiActive", + "lastFeedback", + "addCommandToHistory", + "settings", + "connected", + "pendingSettings", + "setConnected", + "command_id", + "pendingFilter", + "commandHistory", + "value", + "setLastFeedback", + "section", + "setPendingFilter", + "clearPending", + "entity" ], "onboardingStore": [ - "isActive", - "reset", - "step", - "complete", - "start", - "next", - "goToStep", "prev", "skipped", - "completed", + "next", + "complete", "skip", - "data" + "start", + "data", + "reset", + "step", + "isActive", + "completed", + "goToStep" ], "windowStore": [ - "activeWindowId", - "type", - "const", - "updateWindowSize", - "toggleAiChat", - "updateWindowPosition", "component", - "nextZIndex", - "height", "restoreWindow", - "openWindow", - "closeWindow", - "newWindow", - "windows", - "null", - "setActiveWindow", - "aiChatVisible", - "componentProps", - "size", - "zIndex", - "config", "toggleFullscreen", - "position", - "title", + "setActiveWindow", + "height", + "updateWindowPosition", "minimizeWindow", - "width" + "openWindow", + "componentProps", + "closeWindow", + "config", + "windows", + "toggleAiChat", + "position", + "null", + "title", + "width", + "const", + "size", + "type", + "aiChatVisible", + "nextZIndex", + "zIndex", + "activeWindowId", + "updateWindowSize", + "newWindow" ], "commandPaletteStore": [ - "isOpen", - "toggle", + "open", "close", - "open" + "isOpen", + "toggle" ], "pluginToolbarStore": [ - "null", - "items", - "setActivePlugin", - "query", - "updates", - "onClick", - "unregisterPlugin", - "label", "value", - "activePlugin", "updateItem", + "updates", + "items", + "registerItems", + "setActivePlugin", + "onClick", + "label", "plugin", - "registerItems" + "activePlugin", + "null", + "query", + "unregisterPlugin" ], "commStore": [ - "sender_type", - "file_name", - "blocks", - "convId", - "loading", - "setLoading", - "block_type", - "unreadCounts", - "is_archived", - "setTyping", - "messages", - "file_id", - "setMessages", - "is_pinned", - "display_name", - "file_size", - "sender_id", - "setActiveConversation", - "updateConversation", - "setUnread", + "participant_type", + "thumbnail_path", "convs", "participant_id", + "block_type", + "blocks", + "updateConversation", + "file_id", "locked_by", - "created_by_type", - "last_msg_sender_type", - "block_data", - "is_direct", - "thumbnail_path", - "attachments", - "content", - "created_at", - "userIds", - "count", - "reactions", - "activeConversationId", - "participant_type", - "conv", - "content_format", - "edited_at", - "unread_count", - "created_by", - "participants", - "last_msg_preview", - "reply_to_id", - "file_source", - "sort_order", - "conversations", - "conversation_id", - "metadata", - "typingUsers", - "msgs", - "role", + "messages", "last_msg_at", - "setConversations", - "addMessage", + "display_name", + "content_format", + "activeConversationId", + "setActiveConversation", + "is_direct", + "typingUsers", + "count", + "loading", + "convId", + "last_msg_preview", + "file_source", + "role", + "is_archived", + "participants", + "setLoading", "title", + "setConversations", + "sender_type", + "addMessage", + "unread_count", + "is_locked", + "userIds", + "sender_id", + "created_by_type", + "content", + "edited_at", + "setMessages", + "block_data", + "reply_to_id", + "conversations", + "msgs", + "conversation_id", "file_type", - "is_locked" + "unreadCounts", + "metadata", + "sort_order", + "conv", + "file_size", + "created_at", + "attachments", + "file_name", + "setTyping", + "setUnread", + "reactions", + "last_msg_sender_type", + "is_pinned", + "created_by" ], "pluginStore": [ - "getAllPageRoutes", - "path", + "is_core", + "entity_type", + "component", + "detail_tabs", + "loaded", + "display_name", + "label_key", + "setManifests", + "entityType", + "getAllSettingsPages", + "group", "options", + "version", + "permission", "loading", - "default_value", - "reset", + "menu_items", + "manifests", + "getAllDashboardWidgets", "setLoading", "protected", - "icon", - "required", - "display_name", - "component", - "group", - "entityType", - "getAllDashboardWidgets", - "label", - "entity", - "manifests", - "col_span", - "order", - "getDetailTabsForEntity", - "menu_items", - "getAllMenuItems", "parent", - "settings_pages", - "entity_type", - "is_core", + "default_value", + "path", + "order", + "label", + "page_routes", + "row_span", + "getAllMenuItems", + "badge_key", + "col_span", + "icon", + "getCustomFieldsForEntity", + "error", + "getAllPageRoutes", + "field_type", + "reset", + "getDetailTabsForEntity", "custom_fields", "dashboard_widgets", - "detail_tabs", - "version", - "badge_key", - "row_span", - "permission", - "setManifests", - "error", - "label_key", - "loaded", - "field_type", - "getAllSettingsPages", - "page_routes", + "required", "setError", - "getCustomFieldsForEntity" + "settings_pages", + "entity" ], "themeStore": [ - "config", - "applyTheme", - "target", - "toggleDarkMode", - "borderRadius", - "DEFAULT_THEME", - "amount", + "setTheme", "loadFromStorage", + "DEFAULT_THEME", + "scales", "saveToStorage", "primaryColor", - "base", - "scales", + "config", + "amount", + "target", "result", - "fontFamily", "darkMode", - "setTheme", - "accentColor" + "toggleDarkMode", + "fontFamily", + "applyTheme", + "borderRadius", + "accentColor", + "base" ], "uiStore": [ - "suggestionSidebarOpen", + "toggleSidebar", + "collapsed", + "setAISidebarCollapsed", + "setLocale", + "toggleAISidebar", + "toast", + "setAISidebarTab", + "addToast", + "setMessageSidebarCollapsed", + "open", + "sidebarOpen", + "messageSidebarCollapsed", "message", + "setTheme", + "openAISidebarProactive", + "toggleSuggestionSidebar", + "toasts", + "toggleMessageSidebar", + "clearNotifications", "type", "notifications", - "clearNotifications", - "toasts", - "addToast", - "open", - "aiSidebarCollapsed", - "removeNotification", - "collapsed", - "aiSidebarTab", - "locale", "setSidebarOpen", - "theme", - "setAISidebarTab", - "toggleMessageSidebar", - "toggleSidebar", - "toggleSuggestionSidebar", - "toast", - "setAISidebarCollapsed", - "index", - "toggleAISidebar", - "setLocale", - "openAISidebarProactive", - "setTheme", - "messageSidebarCollapsed", - "sidebarOpen", + "aiSidebarTab", "clearToasts", + "locale", + "index", + "removeNotification", "removeToast", - "setMessageSidebarCollapsed" + "aiSidebarCollapsed", + "suggestionSidebarOpen", + "theme" ], "workspaceStore": [ - "visibleModuleKeys", - "reset", - "loading", - "setLoading", - "icon", - "is_default", - "setActiveWorkspace", - "isModuleVisible", - "moduleKey", - "modules", - "module_key", - "is_active", - "setContext", - "context", - "height", - "isLoading", - "hasWorkspaces", - "workspaces", - "menu_order", - "setMyWorkspaces", - "description", - "activeWorkspaceId", - "myWorkspaces", - "workspace_id", - "config", - "is_visible", "widgets", - "widget_key", + "visibleModuleKeys", + "is_active", + "activeWorkspaceId", + "moduleKey", "position_y", + "height", + "description", + "is_visible", + "module_key", "position_x", - "width" + "loading", + "menu_order", + "setContext", + "config", + "setLoading", + "isModuleVisible", + "setMyWorkspaces", + "width", + "context", + "myWorkspaces", + "widget_key", + "workspaces", + "is_default", + "workspace_id", + "icon", + "hasWorkspaces", + "reset", + "isLoading", + "setActiveWorkspace", + "modules" ], "authStore": [ + "setUser", + "last_name", + "first_name", + "setAuthenticated", + "setTenant", "loading", + "field_permissions", + "authed", + "role", + "currentTenant", "setLoading", - "user", - "avatar_url", + "slug", + "isAuthenticated", + "fieldPerms", + "tenants", "logout", "is_system_admin", - "slug", - "setAuthenticated", - "isLoading", - "perms", - "permissions", - "setPermissions", - "setUser", - "tenants", - "email", - "setTenant", - "authed", - "first_name", - "isSystemAdmin", + "user", "tenant", - "fieldPerms", + "setPermissions", + "permissions", "error", - "role", - "field_permissions", - "isAuthenticated", - "last_name", + "perms", + "email", + "avatar_url", + "isLoading", "setError", - "currentTenant" + "isSystemAdmin" ] } } \ No newline at end of file diff --git a/scripts/test_suite/trace_hooks.py b/scripts/test_suite/trace_hooks.py index 6ecf9d5..b61cf3c 100644 --- a/scripts/test_suite/trace_hooks.py +++ b/scripts/test_suite/trace_hooks.py @@ -7,6 +7,23 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent.parent APP = ROOT / "app" +# Simplified patterns — match either single or double quotes separately +PATTERNS_REG = [ + r'register_(?:action|filter)s?\s*\(\s*"([^"]+)"', + r"register_(?:action|filter)s?\s*\(\s*'([^']+)'", + r'register_actions_by_owner\s*\(\s*"([^"]+)"', + r"register_actions_by_owner\s*\(\s*'([^']+)'", +] + +PATTERNS_TRIG = [ + r'do_action\s*\(\s*"([^"]+)"', + r"do_action\s*\(\s*'([^']+)'", + r'apply_filters?\s*\(\s*"([^"]+)"', + r"apply_filters?\s*\(\s*'([^']+)'", + r'trigger\s*\(\s*"([^"]+)"', + r"trigger\s*\(\s*'([^']+)'", +] + def find_hook_registrations(): regs = [] for py in APP.rglob("*.py"): @@ -15,10 +32,9 @@ def find_hook_registrations(): except Exception: continue rel = str(py.relative_to(ROOT)) - for m in re.finditer(r'register_(?:action|filter)s?\s*\(\s*["\']([^"\']+)['"]', content): - regs.append({"file": rel, "hook_type": "action_or_filter", "hook_name": m.group(1)}) - for m in re.finditer(r'register_actions_by_owner\s*\(\s*["\']([^"\']+)['"]', content): - regs.append({"file": rel, "hook_type": "action_group", "hook_name": m.group(1)}) + for pat in PATTERNS_REG: + for m in re.finditer(pat, content): + regs.append({"file": rel, "hook_name": m.group(1)}) return regs def find_hook_triggers(): @@ -29,12 +45,9 @@ def find_hook_triggers(): except Exception: continue rel = str(py.relative_to(ROOT)) - for m in re.finditer(r'do_action\s*\(\s*["\']([^"\']+)['"]', content): - triggers.append({"file": rel, "hook_name": m.group(1), "type": "action"}) - for m in re.finditer(r'apply_filters?\s*\(\s*["\']([^"\']+)['"]', content): - triggers.append({"file": rel, "hook_name": m.group(1), "type": "filter"}) - for m in re.finditer(r'trigger\s*\(\s*["\']([^"\']+)['"]', content): - triggers.append({"file": rel, "hook_name": m.group(1), "type": "trigger"}) + for pat in PATTERNS_TRIG: + for m in re.finditer(pat, content): + triggers.append({"file": rel, "hook_name": m.group(1)}) return triggers def main():