chore: initial snapshot of 2meet-data-optimizer-hivepress-addon v0.1.0
Baseline before backporting wp-data-optimizer v3.0.1-v3.4.6. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
This commit is contained in:
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
/**
|
||||
* WP-CLI commands for the HivePress family integration.
|
||||
*
|
||||
* Registered as a namespace under `wp wpdo hivepress`:
|
||||
*
|
||||
* wp wpdo hivepress detect — list installed HivePress family addons
|
||||
* wp wpdo hivepress score — 8-dimension suitability report
|
||||
* wp wpdo hivepress doctor — health probe each active adapter
|
||||
* wp wpdo hivepress migrate — flip an addon's modules to cutover state
|
||||
* wp wpdo hivepress rollback — reset an addon's modules to idle
|
||||
* wp wpdo hivepress benchmark — run sample query timings (no-op when adapters inactive)
|
||||
*
|
||||
* Per Karpathy guideline: the CLI is a thin wrapper over the introspection
|
||||
* helpers built in Sprints 1-3 (detector / suitability-scorer / benchmark).
|
||||
* No new business logic lives here.
|
||||
*
|
||||
* @package WP_Data_Optimizer
|
||||
* @since 3.0.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'TMDO_CLI_HivePress' ) ) {
|
||||
|
||||
/**
|
||||
* `wp wpdo hivepress <subcommand>` namespace handler.
|
||||
*/
|
||||
class TMDO_CLI_HivePress {
|
||||
|
||||
/**
|
||||
* List installed HivePress family addons + adapter binding state.
|
||||
*
|
||||
* ## OPTIONS
|
||||
*
|
||||
* [--format=<format>]
|
||||
* : Output format (table|json|csv|yaml). Default: table.
|
||||
*
|
||||
* ## EXAMPLES
|
||||
*
|
||||
* wp wpdo hivepress detect
|
||||
* wp wpdo hivepress detect --format=json
|
||||
*
|
||||
* @param array $args Positional args (unused).
|
||||
* @param array $assoc_args Flag args.
|
||||
*
|
||||
* @subcommand detect
|
||||
*/
|
||||
public function detect( $args, $assoc_args ): void { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
||||
unset( $args );
|
||||
$format = (string) ( $assoc_args['format'] ?? 'table' );
|
||||
$detected = class_exists( 'TMDO_HivePress_Detector' )
|
||||
? TMDO_HivePress_Detector::detect()
|
||||
: array();
|
||||
$catalog = class_exists( 'TMDO_HivePress_Detector' )
|
||||
? TMDO_HivePress_Detector::catalog()
|
||||
: array();
|
||||
$bound = class_exists( 'TMDO_HivePress_Bootstrap' )
|
||||
? array_keys( TMDO_HivePress_Bootstrap::adapters() )
|
||||
: array();
|
||||
|
||||
$rows = array();
|
||||
foreach ( $catalog as $slug => $name ) {
|
||||
$rows[] = array(
|
||||
'slug' => $slug,
|
||||
'name' => $name,
|
||||
'detected' => isset( $detected[ $slug ] ) ? 'yes' : 'no',
|
||||
'version' => $detected[ $slug ] ?? '-',
|
||||
'bound' => in_array( $slug, $bound, true ) ? 'yes' : 'no',
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'WP_CLI\\Utils' ) || 'table' === $format ) {
|
||||
WP_CLI::log( '=== HivePress family detection ===' );
|
||||
WP_CLI::log( '' );
|
||||
WP_CLI::log( str_pad( 'slug', 26 ) . str_pad( 'detected', 12 ) . str_pad( 'version', 10 ) . 'bound' );
|
||||
WP_CLI::log( str_repeat( '-', 60 ) );
|
||||
foreach ( $rows as $row ) {
|
||||
WP_CLI::log( str_pad( $row['slug'], 26 ) . str_pad( $row['detected'], 12 ) . str_pad( $row['version'], 10 ) . $row['bound'] );
|
||||
}
|
||||
WP_CLI::log( '' );
|
||||
WP_CLI::success( sprintf( 'Detected %d / %d addons', count( $detected ), count( $catalog ) ) );
|
||||
return;
|
||||
}
|
||||
|
||||
\WP_CLI\Utils\format_items( $format, $rows, array( 'slug', 'name', 'detected', 'version', 'bound' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Show 8-dimension suitability report (per-adapter + aggregate).
|
||||
*
|
||||
* ## OPTIONS
|
||||
*
|
||||
* [--addon=<slug>]
|
||||
* : Filter to a single addon slug.
|
||||
*
|
||||
* [--format=<format>]
|
||||
* : Output format (table|json|yaml). Default: table.
|
||||
*
|
||||
* ## EXAMPLES
|
||||
*
|
||||
* wp wpdo hivepress score
|
||||
* wp wpdo hivepress score --addon=hivepress-reviews
|
||||
* wp wpdo hivepress score --format=json
|
||||
*
|
||||
* @param array $args Positional args (unused).
|
||||
* @param array $assoc_args Flag args.
|
||||
*
|
||||
* @subcommand score
|
||||
*/
|
||||
public function score( $args, $assoc_args ): void { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
||||
unset( $args );
|
||||
if ( ! class_exists( 'TMDO_HivePress_Suitability_Scorer' ) ) {
|
||||
WP_CLI::error( 'TMDO_HivePress_Suitability_Scorer not loaded.' );
|
||||
}
|
||||
$report = TMDO_HivePress_Suitability_Scorer::report();
|
||||
$addon = isset( $assoc_args['addon'] ) ? (string) $assoc_args['addon'] : '';
|
||||
$format = (string) ( $assoc_args['format'] ?? 'table' );
|
||||
|
||||
if ( '' !== $addon ) {
|
||||
if ( ! isset( $report['adapters'][ $addon ] ) ) {
|
||||
WP_CLI::error( sprintf( 'Addon "%s" not active.', $addon ) );
|
||||
}
|
||||
$score = $report['adapters'][ $addon ];
|
||||
if ( 'json' === $format || 'yaml' === $format ) {
|
||||
\WP_CLI\Utils\format_items( $format, array( $score ), array_keys( $score ) );
|
||||
return;
|
||||
}
|
||||
WP_CLI::log( sprintf( '=== Score: %s ===', $addon ) );
|
||||
foreach ( $score as $k => $v ) {
|
||||
WP_CLI::log( sprintf( ' %s: %s', str_pad( $k, 22 ), $v ) );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'json' === $format || 'yaml' === $format ) {
|
||||
\WP_CLI\Utils\format_items( $format, array( $report ), array( 'aggregate', 'adapter_count', 'per_dimension', 'adapters' ) );
|
||||
return;
|
||||
}
|
||||
|
||||
WP_CLI::log( '=== HivePress 8-D Suitability Report ===' );
|
||||
WP_CLI::log( '' );
|
||||
WP_CLI::log( sprintf( 'Active adapters: %d', $report['adapter_count'] ) );
|
||||
WP_CLI::log( sprintf( 'Aggregate score: %s / 10', $report['aggregate'] ) );
|
||||
WP_CLI::log( '' );
|
||||
WP_CLI::log( 'Per-dimension averages:' );
|
||||
foreach ( $report['per_dimension'] as $dim => $avg ) {
|
||||
WP_CLI::log( sprintf( ' %s: %s', str_pad( $dim, 22 ), $avg ) );
|
||||
}
|
||||
WP_CLI::log( '' );
|
||||
WP_CLI::log( 'Per-adapter aggregate:' );
|
||||
foreach ( $report['adapters'] as $slug => $score ) {
|
||||
WP_CLI::log( sprintf( ' %s → %s', str_pad( $slug, 26 ), $score['aggregate'] ?? '-' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run doctor probe for each active adapter.
|
||||
*
|
||||
* ## OPTIONS
|
||||
*
|
||||
* [--addon=<slug>]
|
||||
* : Limit probe to a single addon.
|
||||
*
|
||||
* ## EXAMPLES
|
||||
*
|
||||
* wp wpdo hivepress doctor
|
||||
* wp wpdo hivepress doctor --addon=hivepress-favorites
|
||||
*
|
||||
* @param array $args Positional args (unused).
|
||||
* @param array $assoc_args Flag args.
|
||||
*
|
||||
* @subcommand doctor
|
||||
*/
|
||||
public function doctor( $args, $assoc_args ): void { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
||||
unset( $args );
|
||||
$adapters = class_exists( 'TMDO_HivePress_Bootstrap' )
|
||||
? TMDO_HivePress_Bootstrap::adapters()
|
||||
: array();
|
||||
$only = isset( $assoc_args['addon'] ) ? (string) $assoc_args['addon'] : '';
|
||||
|
||||
$failed = 0;
|
||||
$total = 0;
|
||||
foreach ( $adapters as $slug => $adapter ) {
|
||||
if ( '' !== $only && $slug !== $only ) {
|
||||
continue;
|
||||
}
|
||||
if ( ! $adapter instanceof TMDO_HivePress_Adapter ) {
|
||||
continue;
|
||||
}
|
||||
++$total;
|
||||
$probe = $adapter->doctor_check();
|
||||
if ( ! empty( $probe['ok'] ) ) {
|
||||
WP_CLI::log( sprintf( '✓ %s: %s', $slug, $probe['message'] ?? 'OK' ) );
|
||||
} else {
|
||||
WP_CLI::log( sprintf( '✗ %s: %s', $slug, $probe['message'] ?? 'FAIL' ) );
|
||||
++$failed;
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0 === $total ) {
|
||||
WP_CLI::warning( 'No adapters active. Install HivePress first.' );
|
||||
return;
|
||||
}
|
||||
if ( $failed > 0 ) {
|
||||
WP_CLI::error( sprintf( 'Doctor: %d / %d adapters failed.', $failed, $total ) );
|
||||
}
|
||||
WP_CLI::success( sprintf( 'Doctor: %d / %d adapters healthy.', $total, $total ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Flip an addon's modules to a target FSM state (default: cutover).
|
||||
*
|
||||
* ## OPTIONS
|
||||
*
|
||||
* <slug>
|
||||
* : Addon slug (e.g. hivepress-reviews).
|
||||
*
|
||||
* [--state=<state>]
|
||||
* : Target state. One of: dual_write, backfill, verify, cutover, cleanup, complete. Default: cutover.
|
||||
*
|
||||
* ## EXAMPLES
|
||||
*
|
||||
* wp wpdo hivepress migrate hivepress-reviews
|
||||
* wp wpdo hivepress migrate hivepress-favorites --state=dual_write
|
||||
*
|
||||
* @param array $args Positional args (slug).
|
||||
* @param array $assoc_args Flag args.
|
||||
*
|
||||
* @subcommand migrate
|
||||
*/
|
||||
public function migrate( $args, $assoc_args ): void {
|
||||
$slug = (string) ( $args[0] ?? '' );
|
||||
$state = (string) ( $assoc_args['state'] ?? 'cutover' );
|
||||
$this->set_state( $slug, $state );
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll an addon's modules back to idle.
|
||||
*
|
||||
* ## OPTIONS
|
||||
*
|
||||
* <slug>
|
||||
* : Addon slug.
|
||||
*
|
||||
* ## EXAMPLES
|
||||
*
|
||||
* wp wpdo hivepress rollback hivepress-reviews
|
||||
*
|
||||
* @param array $args Positional args (slug).
|
||||
* @param array $assoc_args Flag args (unused).
|
||||
*
|
||||
* @subcommand rollback
|
||||
*/
|
||||
public function rollback( $args, $assoc_args ): void { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
||||
unset( $assoc_args );
|
||||
$slug = (string) ( $args[0] ?? '' );
|
||||
$this->set_state( $slug, 'idle' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Run benchmark suite for active adapters.
|
||||
*
|
||||
* Currently a placeholder that reports availability — real query-pair
|
||||
* benchmarks are wired by individual addons during their migration
|
||||
* tooling. This command lists which adapters can be benchmarked.
|
||||
*
|
||||
* ## EXAMPLES
|
||||
*
|
||||
* wp wpdo hivepress benchmark
|
||||
*
|
||||
* @param array $args Positional args (unused).
|
||||
* @param array $assoc_args Flag args (unused).
|
||||
*
|
||||
* @subcommand benchmark
|
||||
*/
|
||||
public function benchmark( $args, $assoc_args ): void { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
||||
unset( $args, $assoc_args );
|
||||
if ( ! class_exists( 'TMDO_HivePress_Benchmark' ) ) {
|
||||
WP_CLI::error( 'TMDO_HivePress_Benchmark not loaded.' );
|
||||
}
|
||||
$adapters = class_exists( 'TMDO_HivePress_Bootstrap' )
|
||||
? TMDO_HivePress_Bootstrap::adapters()
|
||||
: array();
|
||||
|
||||
if ( empty( $adapters ) ) {
|
||||
WP_CLI::warning( 'No adapters active — no benchmark to run.' );
|
||||
return;
|
||||
}
|
||||
|
||||
WP_CLI::log( '=== HivePress benchmark availability ===' );
|
||||
foreach ( $adapters as $slug => $adapter ) {
|
||||
$mods = $adapter instanceof TMDO_HivePress_Adapter ? $adapter->migrations() : array();
|
||||
if ( empty( $mods ) ) {
|
||||
WP_CLI::log( sprintf( ' %s: no FSM modules', $slug ) );
|
||||
continue;
|
||||
}
|
||||
WP_CLI::log( sprintf( ' %s: %s', $slug, implode( ', ', $mods ) ) );
|
||||
}
|
||||
WP_CLI::log( '' );
|
||||
WP_CLI::log( 'Run `wp wpdo benchmark <module>` for per-module timings.' );
|
||||
}
|
||||
|
||||
// ── Internal helpers ────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Apply a target FSM state to all modules owned by an addon's adapter.
|
||||
*
|
||||
* @param string $slug Addon slug.
|
||||
* @param string $state Target state.
|
||||
*/
|
||||
private function set_state( string $slug, string $state ): void {
|
||||
if ( '' === $slug ) {
|
||||
WP_CLI::error( 'Missing addon slug.' );
|
||||
}
|
||||
if ( ! in_array( $state, TMDO_Feature_Flags::VALID_STATES, true ) ) {
|
||||
WP_CLI::error( sprintf( 'Invalid state "%s". Valid: %s', $state, implode( ', ', TMDO_Feature_Flags::VALID_STATES ) ) );
|
||||
}
|
||||
|
||||
$adapter = class_exists( 'TMDO_HivePress_Bootstrap' )
|
||||
? TMDO_HivePress_Bootstrap::adapter_for( $slug )
|
||||
: null;
|
||||
if ( ! $adapter instanceof TMDO_HivePress_Adapter ) {
|
||||
WP_CLI::error( sprintf( 'Adapter "%s" not active.', $slug ) );
|
||||
}
|
||||
|
||||
$modules = $adapter->migrations();
|
||||
if ( empty( $modules ) ) {
|
||||
WP_CLI::warning( sprintf( 'Adapter "%s" has no FSM modules.', $slug ) );
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $modules as $module ) {
|
||||
TMDO_Feature_Flags::set( (string) $module, $state );
|
||||
WP_CLI::log( sprintf( ' %s → %s', $module, $state ) );
|
||||
}
|
||||
WP_CLI::success( sprintf( 'Adapter "%s" modules set to %s.', $slug, $state ) );
|
||||
}
|
||||
}
|
||||
|
||||
} // end if ( ! class_exists )
|
||||
Reference in New Issue
Block a user