From bd1d484e74b242ffa320ba9eaec6440f9dfb00d2 Mon Sep 17 00:00:00 2001 From: Chaim Date: Wed, 27 May 2026 09:36:42 +0000 Subject: [PATCH] fix(2.10.2): AfterInstall must be a no-namespace class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EspoCRM's extension installer (ExtensionManager.php → Base.php:397) does require_once on scripts/AfterInstall.php and then `new AfterInstall()` without any namespace prefix. The 2.10.0/2.10.1 version had `namespace Espo\Modules\SmartAssistant\Scripts;` which resolved at install time to "Class AfterInstall not found" and aborted the install with HTTP 500 from KlearBrandingExtension/action/install. Match the pattern used by GoogleIntegration/scripts/AfterInstall.php: plain top-level class, no namespace, optional `use` for the Container type hint. Same behavior (idempotent seed of 7 AssistantPrompt rows with skipAll), just loadable. Co-Authored-By: Claude Opus 4.7 (1M context) --- manifest.json | 2 +- scripts/AfterInstall.php | 43 +++++++++++++++++----------------------- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/manifest.json b/manifest.json index 596cb8e..8818e41 100644 --- a/manifest.json +++ b/manifest.json @@ -3,7 +3,7 @@ "module": "SmartAssistant", "description": "Unified AI Assistant for Legal CRM — floating chat with case memory, office alerts, and AI Gateway integration", "author": "klear", - "version": "2.10.1", + "version": "2.10.2", "acceptableVersions": [ ">=8.0.0" ], diff --git a/scripts/AfterInstall.php b/scripts/AfterInstall.php index bef0447..d769762 100644 --- a/scripts/AfterInstall.php +++ b/scripts/AfterInstall.php @@ -1,16 +1,19 @@ get('entityManager'); $log = $container->get('log'); - $resourceFile = __DIR__ . '/../files/custom/Espo/Modules/SmartAssistant/Resources/data/default-prompts.json'; + // The JSON file lives inside the installed module resources at runtime. + $resourceFile = 'custom/Espo/Modules/SmartAssistant/Resources/data/default-prompts.json'; if (!is_file($resourceFile)) { - // Fall back to the module Resources path when the extension is - // installed (Resources/ is the canonical location at runtime). - $resourceFile = dirname(__DIR__) . '/files/custom/Espo/Modules/SmartAssistant/Resources/data/default-prompts.json'; - } - - if (!is_file($resourceFile)) { - // Final fallback: the module's installed Resources path. - $resourceFile = 'custom/Espo/Modules/SmartAssistant/Resources/data/default-prompts.json'; - } - - if (!is_file($resourceFile)) { - $log->warning("[SmartAssistant] AfterInstall: default-prompts.json not found, skipping seed"); + $log->warning("[SmartAssistant] AfterInstall: $resourceFile not found, skipping seed"); return; } @@ -40,7 +33,7 @@ class AfterInstall $defaults = json_decode($json, true); if (!is_array($defaults)) { - $log->warning("[SmartAssistant] AfterInstall: default-prompts.json invalid JSON"); + $log->warning("[SmartAssistant] AfterInstall: invalid JSON in $resourceFile"); return; } @@ -73,8 +66,8 @@ class AfterInstall 'isActive' => true, ]); // skipAll bypasses beforeSave hooks that require a logged-in user - // service (install runs without a session) and ACL checks (we're - // seeding firm-wide defaults; no user is implicated). + // service (installer runs without an HTTP session) and ACL checks + // (we're seeding firm-wide defaults; no user is implicated). $entityManager->saveEntity($entity, ['skipAll' => true]); $created++; }