Paid-launch readiness: Freemius licensing, packaging, build & CI#332
Open
mumega848 wants to merge 27 commits into
Open
Paid-launch readiness: Freemius licensing, packaging, build & CI#332mumega848 wants to merge 27 commits into
mumega848 wants to merge 27 commits into
Conversation
Establish a single source of truth for plan and pro_active so MCP/REST/CLI
can no longer report a free plan while pro is active.
- Add Spai_License::get_license_info() canonical accessor that returns a
self-validated, consistent {plan, is_pro, is_paying, is_agency} snapshot.
- Derive capabilities plan/pro_active in Spai_Core from that accessor after
the spai_site_capabilities filter, and use it for site-info + cache match.
- Stop Spai_Pro_Bootstrap from hardcoding plan/pro_active; keep only the
genuine pro-module-only flags (learnpress, tp_events).
- Align REST MCP is_pro_active() and REST site onboard to the canonical value.
- Make the CLI --test plan display read the unified value without contradictory
defaulting.
- Add LicenseCapabilitiesTest covering the unlicensed/trial/pro/agency/expired/
WP.org matrix and extend the test bootstrap with the needed stubs.
https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
The Tools tab lets admins disable whole MCP tool categories via the spai_disabled_tool_categories option. This was applied at discovery time in get_all_tools() (hiding tools from tools/list) but handle_tools_call() never consulted it, so a tool in an admin-disabled category was hidden from listings yet still fully executable via a direct tools/call. Add a global gate in handle_tools_call() (after the unknown-tool check, before the per-key role check) that rejects any tool whose category is in the disabled list with a -32003 error. The gate applies regardless of the API key's role, keeping discovery and execution consistent. Add DisabledToolCategoriesTest regression coverage for the full cycle. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
Remove the vestigial Lemon Squeezy integration, the dead local license-key store (spai_pro_license), and the dead local trial mechanism (spai_trial_started) from Spai_License so entitlement is resolved entirely through Freemius (plus the SPAI_WPORG_BUILD and MUMCP_PRO build/dev overrides). - is_pro/is_paying/get_plan/is_trial_active now read only from Freemius via spai_get_fs_instance(); get_license_info() keeps its #319 shape and consistency guarantees. - Drop activate()/deactivate() (Lemon Squeezy API calls), get_license_data/key/expiration/is_expired/site_limit, start_trial, get_trial_days_remaining, get_info() (hardcoded lemon_squeezy), and the OPTION_KEY/TRIAL_KEY/TRIAL_DAYS constants and $license_data. - Rework LicenseCapabilitiesTest to simulate every state by stubbing the Freemius instance instead of the removed options; add a configurable Freemius double to the test bootstrap. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
Relocate 25 MCP tools from the free registry to the Pro registry so they are only exposed when an entitlement is active. The Pro registry is merged in get_all_tools/categories/map only when is_pro_active(), so moving the schema, route map, and category for each tool hides it from non-Pro users. Moved (free -> pro): - SEO intelligence (11): readiness, structured data, media SEO, site audit, content quality, issues, autofix plan, search-performance import/trends, WooCommerce SEO report, content coherence report. - Event store / outbound webhooks (9): full 'webhooks' category, including the webhook CRUD/test/logs tools and event listing/schema tools. - Approval / rollback (4): wp_list_approvals, wp_get_approval, wp_apply_approval, wp_rollback_approval. wp_approve_request and wp_reject_request intentionally stay free (not named, no *approval* match). - Site-state snapshot (1): wp_get_site_state only. Underlying REST routes are unchanged and still live on free-tier controllers, so they resolve for Pro clients via the merged map. Add McpProGatingTest covering absence for non-pro and presence for pro, plus an is_multisite() bootstrap stub needed to exercise Pro::get_tools(). https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8 (cherry picked from commit 63cf3ee38d6c8ed9809ad4361979adfab78f97cc)
Complete the agent-safety approval-system gating: the approve/reject actions on pending mutation requests now live in the Pro registry with the rest of the approval/rollback tools, so a free user can no longer act on pending requests. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
- Pro::get_tools() appended the two Google Indexing tools to the wrong local array ($tools[] vs $pro_tools[]), so they were never returned even to Pro users. Corrected so wp_submit_to_google_index and wp_google_index_status are now registered. - handle_tools_call() now returns an actionable -32003 "requires a Pro license" error with an upgrade URL when a non-Pro site calls a Pro-gated tool, instead of a generic "Unknown tool" response (#327). https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
Fix stale assumptions in the V3 plan and product roadmap: billing is Freemius (not Stripe; Stripe only for a future hosted dashboard), tool count is ~250+ (not "239"; exact count tracked in #322), and unify the operator-polish and agency-SaaS theses around the agent-safety + SEO-intelligence paid moat. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
Clean up the $supported_themes array in the active Pro themes handler: remove duplicate 'flavor' array keys and the junk 'flavor'/'flavflavor' placeholder entries, and correct the OceanWP option_key from the bogus 'theme_mods_flavor' to 'ocean_options'. The remaining entries (astra, generatepress, kadence, oceanwp) are now internally consistent with no duplicate keys; astra/generatepress/kadence dispatch to their existing get_/update_<slug>_settings handlers, and oceanwp falls back to the generic theme_mods handlers. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
Replace stale free-only and "239 tools" claims across public-facing copy to match the Freemius free/Operator/Agency model. - #317/#318: frame WP.org build as the free core; paid tiers unlock the agent-safety and SEO-intelligence layers. - #322: replace "239"/"Up to 239" with verified counts (119 free + 137 Pro = 250+); exact accounting tracked in #322. - #331: lead value prop with outcomes (approval-safe edits + rollback, SEO intelligence, content coherence, site-state, Control Room). - #330: add "Works with any agent runtime" sections (MCP-neutral; supplier to Bedrock AgentCore, Antigravity, Managed Agents, etc). https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
The shipped product is the single-distribution Freemius build: build.sh and scripts/release_freemius.sh package only site-pilot-ai/ (paid build keeps includes/pro/, WP.org build strips it). The standalone site-pilot-ai-pro addon plugin used the older free-plugin + pro-addon model, is referenced by no build script, CI workflow, or the active plugin, and carried a divergent (and corrupted) copy of the Pro code. Removing it eliminates the duplicate source of truth. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
Reflect the single-distribution model: Pro Elementor endpoints load from includes/pro/ when licensed, not from the retired standalone plugin. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
- Remove the abandoned plugin/wp-ai-operator.php prototype and the empty stray ziQ9IgA7 file (both were already excluded from builds). - build.sh: strip includes/class-spai-updater.php from the WP.org package (WP.org handles updates; the updater load is guarded by file_exists, so its absence is safe). The paid build keeps it. - build.sh: remove stale dist zips before packaging, since `zip -r` appends to an existing archive and was retaining removed files across rebuilds. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
- Replace the duplicated inline zip logic with a single build.sh call, so the workflow and local builds share one source of truth. This also fixes the shipped zips' top folder being named site-pilot-ai-temp instead of site-pilot-ai, and inherits the WP.org updater strip. - Add secret-gated, no-op-by-default steps to upload the paid build to Freemius (#324) and deploy the WP.org build to plugin SVN (#325). Neither runs until the corresponding repository secrets are set. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
The release-metadata consistency check hardcoded the old spai-updates/mumega-site-pilot-ai-latest.zip URL, which no longer matches version.json's current mcp-updates/mumega-mcp-latest.zip (rebranded to MCPWP, canonical path per #323). This was failing the PHP 8.2 validation job (and fail-fast cancelled the sibling PHP jobs) on every PR. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
… notes (#329) Replace hardcoded "239 tools" with accurate "~119 free / 250+ with Pro integrations" framing in docs/blog-launch-post.md (5 occurrences) and docs/demo-script.md (1 occurrence). Also corrects the demo-script blueprint count from 24 to 14. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8 (cherry picked from commit e859bc6f69527a6b69d29d86e69547b61be6510d)
The blueprint catalog (Spai_Page_Builder::get_blueprint_catalog) defines exactly 24 blueprints, matching the README. A prior edit had set 14. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
…efs #322) - mcp-server/src/index.ts: use MCPWP brand in --version and --help output; replace dead Mumega-com/mcp-for-wp repo URL with canonical mcpwp.net in docs - mcp-server/server.json, mcp-server/package.json: update repo URL to github.com/mumega-com/mcpwp - mcp-server/README.md: update repo URLs to mumega-com/mcpwp; fix tool count from stale 200+ to 250+ - README.md: update repo URLs to mumega-com/mcpwp; fix tool count from stale 239 to 250+ in badge, comparison table, tools section, and roadmap https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8 (cherry picked from commit e9a3635c405f2a8ea0b6aa1710620f3dd77170d8)
Re-applies the GitHub URL rename from the naming cleanup that was dropped when resolving the README merge (the tool-count fixes were already in). https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
Review found four block tools (wp_parse_blocks, wp_serialize_blocks, wp_validate_blocks, wp_get_block_design_system) and two auto menu-item tools were registered but absent from get_tool_categories(), so they fell back to the gate's default 'site' category. With the new execution-time category enforcement this meant disabling 'gutenberg' failed to block the block tools, while disabling 'site' wrongly blocked them. Map the block tools to 'gutenberg' and the menu tools to 'site' (their correct homes). https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
The oceanwp slug was listed as supported but had no settings handler, so get_settings() silently fell through to generic theme_mods while detect_theme() still advertised settings_type=custom_option. Add real get_/update_oceanwp_settings() that read/write the ocean_options option (OceanWP's actual storage). Also correct two misleading metadata claims: kadence's option_key was theme_mods_kadence but get_kadence_settings() reads theme_mods, and get_settings_type() reported every supported theme as custom_option even though kadence is theme_mods-backed. Drive settings_type from a per-theme storage field so the reported type matches what each handler actually reads. The duplicate site-pilot-ai-pro copy of this class is already removed on this branch, so a single canonical handler remains. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
Per the finish-or-demote decision on #329: Forms, Events (ThimPress), and Multilingual are narrow/partial and are not core Pro value, so mark them experimental and stop presenting them as paid features. LearnPress stays a full Pro integration (already documented as Full CRUD). - COMPATIBILITY.md: add a Pro-value-vs-experimental note; mark Forms read-only/experimental; add honest experimental entries for Multilingual (writes WPML/Polylang only, TranslatePress detection-only) and Events (thin tp_event CRUD, no ticketing/registration). - API.md: correct the false "Full multilingual ... TranslatePress" claim, relabel Forms and Multilanguage as experimental, fix the TOC anchor. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
CONTRIBUTING still used the old "mumcp" name and the stale "239 tools" count. Align with the README's MCPWP brand and 250+ count. https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this does
This branch started as the Freemius licensing migration and grew into the paid-launch readiness work for MCPWP: licensing single-source-of-truth, free/paid packaging, positioning/copy accuracy, build + release pipeline, naming cleanup, and CI fixes.
1. Licensing — Freemius as single source of truth
activate()/deactivate(), trial tracking, expiration, Lemon Squeezy calls).get_license_info()accessor returns one self-validating snapshot (plan,is_pro,is_paying,is_agency) used by REST, MCP, CLI, and admin — guaranteeingis_pro=false ⇒ plan=unlicensedandis_pro=true ⇒ plan never free/unlicensed.SPAI_WPORG_BUILD(force free) andMUMCP_PRO(force pro).2. Tool-category governance
tools/call), not just discovery — closing a gap where a known tool name could still be invoked.wp_parse_blocks,wp_serialize_blocks,wp_validate_blocks,wp_get_block_design_system) and two auto menu-item tools were registered but missing from the category map, so they defaulted tosite. Mapped block tools →gutenberg, menu tools →siteso the gate behaves correctly in both directions.3. Packaging & release
build.shis now the single source of truth for both zips; the WP.org build stripsincludes/pro/and the self-hosted updater (WordPress.org handles updates; the updater load is guarded byfile_exists). Fixed a stale-zip accumulation bug (zip -rappends).release.ymlnow callsbuild.shinstead of duplicating zip logic — this also fixes the shipped zip's top folder being namedsite-pilot-ai-tempinstead ofsite-pilot-ai.4. Positioning, docs & naming
mumega-com/mcpwp, docs URL → mcpwp.net. Functional identifiers (text domainsite-pilot-ai,spai_prefix, npm name, config dir) deliberately left unchanged — see follow-ups.plugin/wp-ai-operator.phpprototype and the legacysite-pilot-ai-pro/standalone tree (the large deletion in this diff).5. CI fix
validate.yml's metadata check hardcoded the oldspai-updates/...updater URL, which no longer matchedversion.json'smcp-updates/mumega-mcp-latest.zip— this was failing the PHP 8.2 job (and fail-fast cancelled the rest) on every PR. Updated to the canonical URL.Review notes / follow-ups (not blocking, for the author to confirm)
/wp-json/spai/v1/approvals/*usesverify_api_keyonly (no license gate). Confirm whether approvals via REST should also be license-gated (and whetherSpai_Approvalseven loads on free).is_pro_active()callsget_license_info()~6×/tools/call; a per-request memo would remove redundant Freemius lookups.How to test
cd site-pilot-ai && vendor/bin/phpunit --bootstrap tests/bootstrap.php tests(59 tests green)../build.sh→ verifydist/site-pilot-ai-wporg.zipexcludesincludes/pro/and the updater,dist/site-pilot-ai.zipincludes both, both with asite-pilot-ai/root folder.GET /site-pilot-ai/v1/site/inforeports consistentplan/is_profor each Freemius state;MUMCP_PROandSPAI_WPORG_BUILDoverrides behave as documented.tools/callfor that category returns-32003, and that disablinggutenbergnow blockswp_parse_blocks.https://claude.ai/code/session_017aUcY2VsN82yQ2AocAuHD8