PHP plugin integrating Parallels Plesk/Virtuozzo license management into MyAdmin via the KA (Key Administrator) API.
composer install # install deps
composer test # run all tests
composer test tests/PluginTest.php # plugin class tests
composer test tests/ParallelsIncTest.php # inc function tests- Plugin class:
src/Plugin.php· namespaceDetain\MyAdminParallels· registers event hooks viagetHooks() - Functions:
src/parallels.inc.php· procedural · exportsactivate_parallels(),deactivate_parallels(),deactivate_parallels_by_key() - KA API client:
\Detain\Parallels\Parallels(fromdetain/parallels-licensing) · methods:createKey(),getKeyNumbers(),terminateKey(),retrieveKey(),getKeyInfo(),getAvailableUpgrades(),getAvailableKeyTypesAndFeatures() - CLI scripts:
bin/parallels.php,bin/parallels_getKeyInfo.php,bin/parallels_getKeyNumbers.php,bin/parallels_retrieveKey.php,bin/parallels_getAvailableUpgrades.php,bin/parallels_getAvailableKeyTypesAndFeatures.php· each requires../../../../include/functions.inc.php - Tests:
tests/PluginTest.php,tests/ParallelsIncTest.php· bootstrap stubs intests/bootstrap.php - Config:
phpunit.xml.dist· autoload:Detain\MyAdminParallels\→src/,Detain\MyAdminParallels\Tests\→tests/ - CI/Workflows:
.github/contains GitHub Actions workflows for automated testing and deployment pipelines - IDE Config:
.idea/contains project-specific IDE settings includinginspectionProfiles/,deployment.xml, andencodings.xml
// In Plugin::getHooks()
self::$module.'.activate' => [__CLASS__, 'getActivate'],
// Handler — always static, accepts GenericEvent
public static function getActivate(GenericEvent $event) {
$serviceClass = $event->getSubject();
if ($event['category'] == get_service_define('PARALLELS')) {
myadmin_log(self::$module, 'info', 'Message', __LINE__, __FILE__, self::$module, $serviceClass->getId());
function_requirements('activate_parallels');
// ... call inc function ...
$event->stopPropagation();
}
}// In src/parallels.inc.php
function activate_parallels($ipAddress, $type, $addons = '') {
myadmin_log('licenses', 'info', "message", __LINE__, __FILE__);
$parallels = new \Detain\Parallels\Parallels();
try {
$response = $parallels->createKey($type, $addonsArray, $ipAddress);
request_log('licenses', false, __FUNCTION__, 'parallels', 'createKey', $request, $response);
} catch (\XML_RPC2_CurlException $e) {
request_log('licenses', false, __FUNCTION__, 'parallels', 'createKey', $request, $e->getMessage());
return false;
}
return $response;
}tests/bootstrap.php stubs: myadmin_log(), get_service_define(), function_requirements(), request_log(), get_module_settings(). Add new stubs here when src/ code calls additional MyAdmin globals.
- Module name:
licenses(used inmyadmin_log()andPlugin::$module) - Always call
$event->stopPropagation()after handling in event handlers - Check
$event['category'] == get_service_define('PARALLELS')before acting - Log both before and after KA API calls using
myadmin_log()+request_log() - Deactivation writes termination state to
../../../../include/config/plesk.json - Settings registered via
$settings->add_text_setting()/add_password_setting()/add_dropdown_setting()
IMPORTANT: Before every git commit, you MUST ensure Caliber syncs agent configs with the latest code changes.
First, check if the pre-commit hook is already installed:
grep -q "caliber" .git/hooks/pre-commit 2>/dev/null && echo "hook-active" || echo "no-hook"- If hook-active: the hook handles sync automatically — just commit normally. Tell the user: "Caliber will sync your agent configs automatically via the pre-commit hook."
- If no-hook: run Caliber manually before committing:
- Tell the user: "Caliber: Syncing agent configs with your latest changes..."
- Run:
caliber refresh && git add CLAUDE.md .claude/ .cursor/ .cursorrules .github/copilot-instructions.md .github/instructions/ AGENTS.md CALIBER_LEARNINGS.md .agents/ .opencode/ 2>/dev/null - After it completes, briefly tell the user what Caliber updated. Then proceed with the commit.
If caliber is not found, tell the user: "This project uses Caliber for agent config sync. Run /setup-caliber to get set up."
Read CALIBER_LEARNINGS.md for patterns and anti-patterns learned from previous sessions.
These are auto-extracted from real tool usage — treat them as project-specific rules.