From 12c9c1964628972a21c808b34fe91dc7120a8354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eW=C9=98yn?= <5607939+Llewellynvdm@users.noreply.github.com> Date: Tue, 29 Sep 2026 10:42:04 +0200 Subject: [PATCH 1/3] Fix independent console plugin release compatibility --- AGENTS.md | 1 + CHANGELOG.md | 6 ++++++ README.md | 2 +- docs/IMPLEMENTATION.md | 8 +++++--- joomengine_mcp_changelog.xml | 9 +++++++++ src/Installer/InstallerScript.php | 4 +--- 6 files changed, 23 insertions(+), 7 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 273a0c4..dfc8d6b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -19,6 +19,7 @@ Run syntax, provider/registration, manifest/package tests and coordinated instal ## Source installation and releases - This repository is exclusively the console plugin. Its GitHub source ZIP must install directly into a Joomla site with the compatible component installed. Keep every manifest file tracked; no build, Composer run or repacking is required downstream. +- Component and plugin releases have independent versions. Keep the explicit minimum component version and shared typed runtime contract; never infer component compatibility from the plugin's own major version. Verify dependency checks against independently versioned releases. - Do not add plugin/package builders, copied component dependencies, combined package manifests or package feeds. The component's release invokes OctoJPack using its standalone `.octojpack` configuration, which selects this plugin's latest tag. The resulting Joomla package belongs to its own repository. - The manual Release workflow accepts the next version, freezes manifest/changelog metadata, creates an immutable tag, adds its source ZIP to this plugin's Joomla update feed, and waits for OctoShoom to commit the checksum. This workflow never invokes OctoJPack. Keep the fixed `joomengine/mcp_plugin` repository, `main` branch and feed path in the workflow; never move an existing tag. - Use `octoleo/git-user@v2` and `octoleo/octoshoom@master` directly as actions, following their quick starts. Configure authentication once through git-user's documented secrets; let OctoShoom inherit it. Do not add custom SSH setup, action checkouts, repository discovery, hash rechecks or wrappers around the shared tools. Local release support only freezes version metadata and appends the Joomla update entry. Engine changes require an explicit request. diff --git a/CHANGELOG.md b/CHANGELOG.md index fa5cc7b..864e986 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [[[NEXT_VERSION]]] + +### Fix + +- Allow independently versioned component and console plugin releases to install together; retain the component 0.1.1 minimum, enabled state and runtime dependency checks. + ## 1.0.0 ### Fix diff --git a/README.md b/README.md index a419391..e6f268f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ PHP-only local Joomla console integration for `com_joomengine_mcp`. -Requires component version **0.1.1 or later in the same major version**, including its explicit JCB synchronization runtime. +Requires component version **0.1.1 or later**, including its explicit JCB synchronization runtime. Component and plugin release versions are independent; the shared console runtime interfaces establish compatibility. **Element:** `joomengine_mcp` **Group:** `console` diff --git a/docs/IMPLEMENTATION.md b/docs/IMPLEMENTATION.md index 162c86c..3e8fb47 100644 --- a/docs/IMPLEMENTATION.md +++ b/docs/IMPLEMENTATION.md @@ -1,10 +1,12 @@ -# Implementation status — 28 September 2026 +# Implementation status — 29 September 2026 ## Branch -The migration [PR #1](https://github.com/joomengine/mcp_plugin/pull/1) is merged. First-package release readiness is on `fix/first-package-release`; the [component acceptance checklist](https://github.com/joomengine/mcp_component/pull/1#issuecomment-5732685349) tracks coordinated Joomla/JCB execution evidence. +The migration [PR #1](https://github.com/joomengine/mcp_plugin/pull/1) and first-package readiness changes are merged. Independent release compatibility is being corrected on `fix/independent-plugin-version`; the [component acceptance checklist](https://github.com/joomengine/mcp_component/pull/1#issuecomment-5732685349) tracks coordinated Joomla/JCB execution evidence. -Plugin version 0.1.0 requires component version 0.1.1 or later within the same major version, because the explicit JCB synchronization operation is part of that runtime contract. +The plugin requires component version 0.1.1 or later, because the explicit JCB synchronization operation is part of that runtime contract. Component and plugin versions are independent. Installation checks the minimum component version, enabled state and runtime autoloader; execution retains the shared ConsoleRuntimeProviderInterface and ConsoleRuntimeInterface checks. + +The [v1.0.0 installed CI failure](https://github.com/joomengine/mcp_plugin/actions/runs/36455842922/job/109042215043) exposed an incorrect major-version equality check: plugin 1.0.0 rejected component 0.1.1 despite its compatible runtime. This fix removes that coupling without changing either published version or tag. A subsequent plugin release is required to distribute the corrected installer. ## Implemented runtime diff --git a/joomengine_mcp_changelog.xml b/joomengine_mcp_changelog.xml index a1c9ae0..8e14061 100644 --- a/joomengine_mcp_changelog.xml +++ b/joomengine_mcp_changelog.xml @@ -1,5 +1,14 @@ + + joomengine_mcp + plugin + console + [[[NEXT_VERSION]]] + + Allow independently versioned component and console plugin releases to install together; retain the component 0.1.1 minimum, enabled state and runtime dependency checks. + + joomengine_mcp plugin diff --git a/src/Installer/InstallerScript.php b/src/Installer/InstallerScript.php index 2ff53c3..2478de4 100644 --- a/src/Installer/InstallerScript.php +++ b/src/Installer/InstallerScript.php @@ -61,13 +61,11 @@ public function preflight(string $type, InstallerAdapter $adapter): bool $row = $db->setQuery($query)->loadAssoc(); $manifest = json_decode($row['manifest_cache'] ?? '{}', true); $componentVersion = (string) ($manifest['version'] ?? '0'); - $pluginVersion = (string) $adapter->getManifest()->version; if ($row === null || (int) $row['enabled'] !== 1 || version_compare($componentVersion, '0.1.1', '<') - || explode('.', $componentVersion)[0] !== explode('.', $pluginVersion)[0] || !is_file(JPATH_ADMINISTRATOR . '/components/com_joomengine_mcp/vendor/autoload.php')) { - throw new RuntimeException('Install and enable JoomEngine MCP component version 0.1.1 or later in the same major version before its console plugin.'); + throw new RuntimeException('Install and enable JoomEngine MCP component version 0.1.1 or later before its console plugin.'); } return true; From c0f7637c396c135c95972ab7fe4b57575031ee1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eW=C9=98yn?= <5607939+Llewellynvdm@users.noreply.github.com> Date: Tue, 29 Sep 2026 10:42:34 +0200 Subject: [PATCH 2/3] Cover independent versions in installed dependency checks --- tests/installed.php | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/installed.php b/tests/installed.php index 329e9cb..4eefe6c 100644 --- a/tests/installed.php +++ b/tests/installed.php @@ -7,9 +7,12 @@ * @license GNU General Public License version 3 or later; see LICENSE */ +use Joomla\CMS\Installer\Adapter\PluginAdapter; +use Joomla\CMS\Installer\Installer; use Joomla\Database\DatabaseInterface; use Mcp\Client; use Mcp\Client\Transport\StdioTransport; +use VDM\Plugin\Console\JoomEngineMcp\Installer\InstallerScript; $component = realpath((string) getenv('MCP_COMPONENT_SOURCE')); @@ -42,6 +45,54 @@ echo 'PASS ' . $message . PHP_EOL; }; +// Exercise dependency checks against the real disposable extension registry. +require_once JPATH_PLUGINS . '/console/joomengine_mcp/src/Installer/InstallerScript.php'; +$adapter = new PluginAdapter(new Installer(), $db); +$adapter->setManifest(simplexml_load_file(dirname(__DIR__) . '/joomengine_mcp.xml')); +$installer = new InstallerScript($db, $app); +$componentRecord = $db->setQuery($db->createQuery() + ->select($db->quoteName(['extension_id', 'element', 'enabled', 'manifest_cache'])) + ->from($db->quoteName('#__extensions')) + ->where($db->quoteName('type') . ' = ' . $db->quote('component')) + ->where($db->quoteName('element') . ' = ' . $db->quote('com_joomengine_mcp')))->loadObject(); + +if ($componentRecord === null) +{ + throw new RuntimeException('The installed component registry record is missing.'); +} + +try +{ + $cache = json_decode($componentRecord->manifest_cache, true, 512, JSON_THROW_ON_ERROR); + + foreach (['0.1.1' => true, '1.0.0' => true, '0.1.0' => false] as $version => $supported) + { + $record = clone $componentRecord; + $cache['version'] = $version; + $record->manifest_cache = json_encode($cache, JSON_THROW_ON_ERROR); + $db->updateObject('#__extensions', $record, 'extension_id'); + + foreach (['install', 'update'] as $operation) + { + $check($installer->preflight($operation, $adapter) === $supported, + 'Installer ' . $operation . ' checks component ' . $version . ' independently of the plugin release version'); + } + } + + $record = clone $componentRecord; + $record->enabled = 0; + $db->updateObject('#__extensions', $record, 'extension_id'); + $check(!$installer->preflight('install', $adapter), 'Installer rejects a disabled component'); + $record->element .= '_fixture_missing_' . $record->extension_id; + $db->updateObject('#__extensions', $record, 'extension_id'); + $check(!$installer->preflight('install', $adapter), 'Installer rejects a missing component'); + $check($installer->preflight('uninstall', $adapter), 'Plugin removal remains possible without its component'); +} +finally +{ + $db->updateObject('#__extensions', $componentRecord, 'extension_id'); +} + /** Run the real installed CLI with bounded pipes, a deadline and no shell. */ $run = static function (array $command, string $input = '') use ($arguments): array { From eab466cfb51c9ef51bdb2f18431c2e2fcdafbc3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eW=C9=98yn?= <5607939+Llewellynvdm@users.noreply.github.com> Date: Tue, 29 Sep 2026 10:49:37 +0200 Subject: [PATCH 3/3] Read the installed plugin manifest in shared fixtures --- tests/installed.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/installed.php b/tests/installed.php index 4eefe6c..eacc9ed 100644 --- a/tests/installed.php +++ b/tests/installed.php @@ -48,7 +48,7 @@ // Exercise dependency checks against the real disposable extension registry. require_once JPATH_PLUGINS . '/console/joomengine_mcp/src/Installer/InstallerScript.php'; $adapter = new PluginAdapter(new Installer(), $db); -$adapter->setManifest(simplexml_load_file(dirname(__DIR__) . '/joomengine_mcp.xml')); +$adapter->setManifest(simplexml_load_file(JPATH_PLUGINS . '/console/joomengine_mcp/joomengine_mcp.xml')); $installer = new InstallerScript($db, $app); $componentRecord = $db->setQuery($db->createQuery() ->select($db->quoteName(['extension_id', 'element', 'enabled', 'manifest_cache']))