Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
286 commits
Select commit Hold shift + click to select a range
a52c9af
test: Add PHPUnit tests for Phase 2 MCP tools
LC43 Jun 19, 2026
8f1e354
infra: Finalize Phase 2 project configuration
LC43 Jun 19, 2026
bdd50e2
infra(phpunit): Add Rest test suite to phpunit.xml
LC43 Jun 19, 2026
782fbc1
feature(mcp): Introduce ErrorCode constants
LC43 Jun 19, 2026
a8d18fd
feature(mcp): Add configurable env-var feature flags to Config
LC43 Jun 19, 2026
4f72ebf
feature(mcp): Add in-memory caching layer for WordPressClient GET
LC43 Jun 19, 2026
8a3979d
feature(mcp): Add sliding-window rate limiter for tool calls
LC43 Jun 19, 2026
377d4a1
feature(mcp): Add audit trail logging for tool call tracking
LC43 Jun 19, 2026
d730b89
feature(mcp): Wire Phase 3 hardening features into Server
LC43 Jun 19, 2026
284b7de
docs: Update CURRENT.md reflecting Phase 3 hardening progress
LC43 Jun 19, 2026
77d80c5
docs: Mark completed Phase 3 items in ROADMAP.md
LC43 Jun 19, 2026
3f26317
refactor(mcp-config): Switch to array bag constructor
LC43 Jun 19, 2026
a542762
fix(mcp-error): Remove dead ternary in fromApiError
LC43 Jun 19, 2026
9ace1da
refactor(mcp-error): Remove unused getDefaultMessage method
LC43 Jun 19, 2026
bb15585
refactor(mcp-rate-limiter): Split RateLimitResult into own file
LC43 Jun 19, 2026
8391749
Update roadmap
LC43 Jun 20, 2026
0c2688a
Add REST tests
LC43 Jun 20, 2026
0a5c0e5
Merge main into feature branch
LC43 Jun 28, 2026
a6a1dce
feature(mcp): add ToolFactory for shared tool definitions
LC43 Jun 28, 2026
b6b8619
infra(mcp): switch Server to ToolFactory
LC43 Jun 28, 2026
901a8e0
test(mcp): use createStub in ToolProviderTest
LC43 Jun 28, 2026
1a45089
feature(mcp): add term filter support to ListPosts
LC43 Jun 28, 2026
2bdf924
feature(mcp): add AbilityRegistrar for WordPress-native abilities
LC43 Jun 28, 2026
a22a43f
feature(mcp): add MCP feature class
LC43 Jun 28, 2026
b1f33f3
test(mcp): add MCPFeatureTest
LC43 Jun 28, 2026
e4bb868
feature(models): add API getter methods to models
LC43 Jun 28, 2026
499a778
feature(rest): add taxonomy metadata to model responses
LC43 Jun 28, 2026
1b5b00e
test(rest): use createStub in RestServerTest
LC43 Jun 28, 2026
18f2ad2
docs: update project documentation for MCP v0
LC43 Jun 28, 2026
72019af
infra(testing): add strict flags to phpunit config
LC43 Jun 30, 2026
358027b
infra(testing): add testcase base class for framework tests
LC43 Jun 30, 2026
586d700
infra(testing): add container unit tests
LC43 Jun 30, 2026
f5fe735
infra(testing): add asset data unit test
LC43 Jun 30, 2026
9f0aa14
infra(testing): add model config unit tests
LC43 Jun 30, 2026
a4b8cd0
infra(testing): add integration boot test
LC43 Jun 30, 2026
147152a
fix(ratelimiter): fix race condition in rate limiter test
LC43 Jun 30, 2026
0bad72e
feature(meta): add aggregate meta endpoint for field normalization
LC43 Jun 30, 2026
b615c4a
feature(meta): wire up list_meta_fields through tool factory
LC43 Jun 30, 2026
3f9f269
test(meta): add tests for list_meta_fields tool
LC43 Jun 30, 2026
8790c64
test(meta): add tests for aggregate meta endpoint
LC43 Jun 30, 2026
c2a6a22
infra(ci): add phpunit test job to workflow
LC43 Jun 30, 2026
548d8da
docs(project): update for mcp v0 metadata feature
LC43 Jun 30, 2026
b952496
infra(deps): bump version to 1.4.0
LC43 Jun 30, 2026
1f1eae8
docs(project): bump version to 1.4.0 in roadmap
LC43 Jun 30, 2026
fa89da5
release: bump version to 2.0.0 in source files
LC43 Jun 30, 2026
0a6220b
docs: add v2.0.0 changelog entries
LC43 Jun 30, 2026
5f0d5dc
docs: bump roadmap version to 2.0.0
LC43 Jun 30, 2026
aa7519b
release: merge feature/mcp-v0 into main for v2.0.0
LC43 Jun 30, 2026
cc4e5d0
docs: mark v2.0.0 release as complete in roadmap
LC43 Jun 30, 2026
50a7231
docs: move v2.0.0 release to completed in CURRENT.md
LC43 Jun 30, 2026
71328fd
docs: add v2.0.0 release note to CURRENT.md
LC43 Jun 30, 2026
945d48a
fix(model): add get_name() to Model interface
LC43 Jun 30, 2026
24e1e96
fix(model): implement get_name() in BaseModel
LC43 Jun 30, 2026
2179fda
fix(modeler): use model accessor instead of direct property
LC43 Jun 30, 2026
a6122cd
test: add unit tests for Modeler add/get_models
LC43 Jun 30, 2026
dd977ca
fix(mcp): remove redundant is_string check in ListPosts
LC43 Jun 30, 2026
9b10631
fix(rest): extract namespace string into ROUTE_NAMESPACE constant
LC43 Jun 30, 2026
1925618
infra: add .gitkeep to integration tests directory
LC43 Jun 30, 2026
13633b3
docs: add Unreleased changelog section for PHPStan fixes
LC43 Jun 30, 2026
be3dbd9
Fix notices on tests
LC43 Jun 30, 2026
4a4dd68
Fix notices on more tests
LC43 Jun 30, 2026
4de7060
infra(mcp): add Json helper for safe JSON encoding
LC43 Jun 30, 2026
dc1998a
style(mcp-error): rename Error module to snake_case
LC43 Jun 30, 2026
18011e3
style(mcp-config): rename Config module to snake_case
LC43 Jun 30, 2026
ea28b99
style(mcp-client): rename WordPressClient to snake_case
LC43 Jun 30, 2026
4986b99
style(mcp-validation): rename Validator to snake_case
LC43 Jun 30, 2026
d834a3f
style(mcp-audit): rename Audit module to snake_case
LC43 Jun 30, 2026
adb60b9
style(mcp-rate-limiter): rename RateLimiter module to snake_case
LC43 Jun 30, 2026
96c5238
style(mcp-server): rename Server to snake_case
LC43 Jun 30, 2026
304e9e4
style(mcp-prompts): rename PromptProvider to snake_case
LC43 Jun 30, 2026
3fe652e
style(mcp-resources): rename ResourceProvider to snake_case
LC43 Jun 30, 2026
33c87b0
style(mcp-abilities): rename AbilityRegistrar to snake_case
LC43 Jun 30, 2026
549d2d2
style(mcp-abilities): rename AbilityDefinitionFactory to snake_case
LC43 Jun 30, 2026
cfa9350
style(mcp-feature): rename MCP feature to snake_case
LC43 Jun 30, 2026
b269478
style(mcp-tools-core): rename tool core interfaces to snake_case
LC43 Jun 30, 2026
b0b4b3b
style(mcp-tools): rename get/list tool implementations to snake_case
LC43 Jun 30, 2026
e84d624
style(mcp-tools): rename create/update/delete tool implementations to…
LC43 Jun 30, 2026
11e25ee
test(mcp-tools): update tests for snake_case method names
LC43 Jun 30, 2026
a089b7d
style(container): rename ReflectionClass getName to get_name
LC43 Jun 30, 2026
f67f3d6
style(rest): fix array alignment in REST controllers
LC43 Jun 30, 2026
78d5cd7
fix(container): revert ReflectionClass method to getName
LC43 Jun 30, 2026
898c3c7
docs: Sync project docs after PHPStan fix
LC43 Jun 30, 2026
e5e1313
infra(mcp): Remove standalone stdio MCP server files
LC43 Jul 1, 2026
f1ec227
feature(mcp): Add AbilityRuntime execution engine for WP7 abilities
LC43 Jul 1, 2026
31bc532
feature(mcp): Add AuditDatabase interface decoupling audit from wpdb
LC43 Jul 1, 2026
4c1dde7
feature(mcp): Register cache-clear hooks in MCP feature
LC43 Jul 1, 2026
ef94888
feature(mcp): Strip execution logic from remaining tool definitions
LC43 Jul 1, 2026
c8d4395
feature(mcp): Use fully-qualified function calls in REST controllers
LC43 Jul 1, 2026
7f7d457
test(mcp): Extend test function stubs for transient globals
LC43 Jul 1, 2026
dfa65b2
test(mcp): Update AbilityRegistrar test for runtime integration
LC43 Jul 1, 2026
7141871
test(mcp): Refactor AuditLogger test for wpdb table writes
LC43 Jul 1, 2026
f657ef5
test(mcp): Preserve ToolProvider unit tests unchanged
LC43 Jul 1, 2026
6e0e34c
docs: Sync project docs after MCP server removal
LC43 Jul 1, 2026
9392930
fix(MCP/Audit): Sanitize audit database string fields before insert
LC43 Jul 1, 2026
5ed3e6e
infra(rest): Add RouteDefinition, ModelRestPolicy, RestRouteProvider
LC43 Jul 1, 2026
b5f9e8d
infra(core): Wire Modeler as RestRouteProvider, inject routes into Core
LC43 Jul 1, 2026
a950b48
feature(rest): Gate REST controllers via ModelRestPolicy
LC43 Jul 1, 2026
77db5d9
feature(features): Register as RestRouteProviders for REST access
LC43 Jul 1, 2026
9f07342
fix(mcp): Gate MCP abilities through ModelRestPolicy
LC43 Jul 1, 2026
bb6b819
test(rest): Cover capability-gated REST endpoints, MCP policy
LC43 Jul 1, 2026
22272a9
docs: Record Legacy Refactoring Track, REST capability gating
LC43 Jul 1, 2026
0057ccb
feature(mcp): introduce RestBackedToolInterface types
LC43 Jul 1, 2026
96d8a78
feature(mcp): add @phpstan-type AbilityDefinition definition
LC43 Jul 1, 2026
d1f7438
feature(mcp): refactor AbilityRegistrar per-tool gating
LC43 Jul 1, 2026
299e26e
feature(mcp): extract per-tool dispatch from AbilityRuntime
LC43 Jul 1, 2026
61ff8bb
feature(mcp): extend audit infrastructure
LC43 Jul 1, 2026
8e9a15b
feature(mcp): refactor cache rate-limiter validation
LC43 Jul 1, 2026
eb69be2
feature(mcp): migrate first ten tools to RestBackedToolInterface
LC43 Jul 1, 2026
368debd
feature(mcp): migrate remaining tools to RestBackedToolInterface
LC43 Jul 1, 2026
bf49cb9
feature(mcp): update REST controllers for MCP v1 dispatch
LC43 Jul 1, 2026
6147cd9
feature(mcp): register MCP service in Core boot sequence
LC43 Jul 1, 2026
a32f618
feature(mcp): add ToolContributor to Modeler
LC43 Jul 1, 2026
b55615d
feature(mcp): add lazy tool provider to MCP feature
LC43 Jul 1, 2026
fd7692a
feature(mcp): update container for MCP service wiring
LC43 Jul 1, 2026
028ed19
feature(mcp): add ToolContributor to feature services
LC43 Jul 1, 2026
6891fd0
test(mcp): update tests for MCP v1 dispatch changes
LC43 Jul 1, 2026
a5cc57a
infra(container): fix phpdoc array type annotations
LC43 Jul 1, 2026
f2f604f
infra(core): use self:: for private constant references
LC43 Jul 1, 2026
2ff6de0
feature(rest): delegate permission checks to per-post-type capabilities
LC43 Jul 1, 2026
dcdeb09
feature(mcp): delegate tool permissions to WordPress capabilities
LC43 Jul 1, 2026
f955ba1
test(rest): add tests for per-post-type capability checks
LC43 Jul 1, 2026
13bbbf5
test(mcp): add tests for permission callback delegation
LC43 Jul 1, 2026
1b5232a
docs(roadmap): mark MCP v1 refactoring complete
LC43 Jul 1, 2026
94cd118
docs(current): record MCP v1 refactoring completion
LC43 Jul 1, 2026
bb66875
fix(export): scope REST export to single post instead of full post type
LC43 Jul 2, 2026
133d3c9
fix(core): register lifecycle hooks against consuming plugin file
LC43 Jul 2, 2026
109a170
fix(mcp): fail closed on missing permission callback args
LC43 Jul 2, 2026
4d159c2
fix(settings): preserve structured values during sanitization
LC43 Jul 2, 2026
c170102
fix(assets): bring AssetLoader under PHPStan coverage
LC43 Jul 2, 2026
09c7fde
docs(changelog): record code-review hardening changes
LC43 Jul 2, 2026
cd20fb2
refactor(Modeler): extract process_config to unify ternary dispatch
LC43 Jul 2, 2026
cfc171e
feature(health): add health monitoring REST endpoint
LC43 Jul 2, 2026
46d7dcf
infra(composer): add docs:mcp script for MCP doc generation
LC43 Jul 2, 2026
eaae6dc
test(rest): add HealthControllerTest
LC43 Jul 2, 2026
f3caa96
test(mcp): add get-health assertions to ability tests
LC43 Jul 2, 2026
281e079
test(modeler): assert GetHealth in legacy tool list
LC43 Jul 2, 2026
6c6b826
docs(mcp): add MCP documentation pages
LC43 Jul 2, 2026
107c792
infra(composer): add MCP doc generation script
LC43 Jul 2, 2026
996c2a4
fix(Rest): remove PHP 8.0+ union types for PHP 7.4 compat
LC43 Jul 2, 2026
b72bc22
fix(MCP): remove PHP 8.0+ type hints for PHP 7.4 compat
LC43 Jul 2, 2026
9257dd4
fix(tests): remove PHP 8.0+ features for PHP 7.4 compat
LC43 Jul 2, 2026
d9e411c
docs: update roadmap for health monitoring completion
LC43 Jul 2, 2026
31612c0
infra(core): Guard plugin lifecycle hooks via is_file check
LC43 Jul 3, 2026
b688984
infra(core): Guard asset data iteration against non-AssetData entries
LC43 Jul 3, 2026
0ae66c8
fix(mcp): Guard get_taxonomy return value before cap access
LC43 Jul 3, 2026
e4d8bc4
feature(extract): Create shared service classes for feature modules
LC43 Jul 3, 2026
e655d44
feature(extract): Delegate REST controllers to shared service classes
LC43 Jul 3, 2026
79d5b0c
feature(extract): Wire MCP tools to shared service classes
LC43 Jul 3, 2026
2499b06
test: Cover service extraction through integration tests
LC43 Jul 3, 2026
2b6b606
infra(core): Simplify AssetLoader PhpDoc import via short class name
LC43 Jul 3, 2026
00f87a2
docs: Add service extraction to roadmap short-term goals
LC43 Jul 3, 2026
9f8a0df
docs: Update current state after service extraction refactor
LC43 Jul 3, 2026
32caaaa
Fix phpstan warning for type
LC43 Jul 3, 2026
8e99f77
fix: move audit retention cleanup from write path to daily cron
LC43 Jul 3, 2026
8186a14
fix: register MCP audit cleanup cron on plugin activation
LC43 Jul 3, 2026
18ea76d
fix: guard settings sanitization against non-stringable objects
LC43 Jul 3, 2026
250b4ee
fix: remove WordPress core download headers from REST export
LC43 Jul 3, 2026
354d001
fix: exclude client-side audit outcomes from health degradation
LC43 Jul 3, 2026
9e2913a
docs: record hardening changes
LC43 Jul 3, 2026
3b6e85a
Update docs
LC43 Jul 3, 2026
5c91295
fix: Address code review defensive findings
LC43 Jul 3, 2026
80852f9
fix(audit): preserve millisecond precision in AuditEntry timestamp
LC43 Jul 4, 2026
7963eb9
fix(rest): coalesce null get_json_params in SettingsController
LC43 Jul 4, 2026
7e0f72d
test: use createStub over createMock in HealthControllerTest
LC43 Jul 4, 2026
da1a316
infra: add combined tests script
LC43 Jul 4, 2026
cd56b32
docs: log defensive fix pass in CURRENT.md
LC43 Jul 4, 2026
cf21dea
Simplify timestamp calc
LC43 Jul 4, 2026
4ebab90
infra: add GitHub Actions CI workflow
LC43 Jul 4, 2026
94d0327
Set min php ver
LC43 Jul 4, 2026
da27909
fix: remove mixed type hints from test stubs for PHP 7.4 compatibility
LC43 Jul 4, 2026
60ea77d
fix: add setAccessible to reflection helpers for PHP 7.4
LC43 Jul 4, 2026
fb8c7a6
fix: remove mixed type hint from WordPress stubs
LC43 Jul 4, 2026
e23d977
docs: update test counts in ROADMAP.md
LC43 Jul 4, 2026
8d10a98
docs: add recent changes entry
LC43 Jul 4, 2026
921c526
test: add setAccessible to remaining inline reflection usages
LC43 Jul 4, 2026
477c492
fix: use createFromFormat for PHP 7.4 DateTimeImmutable compat
LC43 Jul 4, 2026
ee877e5
Revert typing on timestamp
LC43 Jul 4, 2026
c10778a
Fix param for date
LC43 Jul 4, 2026
3625c43
Fix tests
LC43 Jul 4, 2026
5c12946
fix(core): defer RestServer instantiation inside rest_api_init callback
LC43 Jul 4, 2026
292984b
fix(mcp): use wp_clear_scheduled_hook for cron cleanup
LC43 Jul 4, 2026
a44673b
perf(mcp): gate ensure_table behind DB version option
LC43 Jul 4, 2026
a25e748
fix(export): use structural regex for single-export query detection
LC43 Jul 4, 2026
2f668d5
fix(export): Throw RuntimeException instead of wp_die for REST safety
LC43 Jul 4, 2026
b4c0648
fix(mcp): Add edit_posts permission checks for read-only tools
LC43 Jul 4, 2026
751d2d4
Fix CS
LC43 Jul 4, 2026
83c2f11
Add fix command
LC43 Jul 4, 2026
8b302be
fix: use get_object_vars instead of property_exists for model args
LC43 Jul 4, 2026
2e5eb4c
fix: catch Throwable instead of Exception in export_wp wrapper
LC43 Jul 4, 2026
1bee584
fix: Defer rest_api_init registration until modeler is initialized
LC43 Jul 5, 2026
7a4e6dc
fix: Guard TransientCache::clear against multiple calls per request
LC43 Jul 5, 2026
9296ed1
fix: Use setTimestamp in AuditEntry to replace createFromFormat
LC43 Jul 5, 2026
caba7b3
fix: Guard against inaccessible rest_base in RestTool
LC43 Jul 5, 2026
d654ada
docs: Record code review fix pass in changelog
LC43 Jul 5, 2026
05a2a0b
Fix tests
LC43 Jul 5, 2026
8d57245
Update docs
LC43 Jul 5, 2026
ac901a1
infra(git): ignore tester.php
LC43 Jul 5, 2026
bab8b22
fix(mcp): only clear cache on non-GET requests
LC43 Jul 5, 2026
14daffe
fix(validation): add integer type support
LC43 Jul 5, 2026
063a30b
fix(assets): return early when assets list is null
LC43 Jul 5, 2026
f5add41
test(integration): add container integration tests
LC43 Jul 5, 2026
655e994
feature(models): extend Model interface
LC43 Jul 5, 2026
4954062
refactor(rest): remove method_exists fallback for Model interface met…
LC43 Jul 5, 2026
ec93652
refactor(meta): remove method_exists fallback for model get_args
LC43 Jul 5, 2026
8e823ed
test(models): implement get_options get_args in model mocks
LC43 Jul 5, 2026
8d3c9d4
test(models): implement get_options get_args in MCP feature mocks
LC43 Jul 5, 2026
dca25f8
infra(git): remove tester.php from tracking
LC43 Jul 5, 2026
bea582d
fix(cache): remove static clear guard from TransientCache
LC43 Jul 5, 2026
572e8d4
fix(settings): verify update_option failure via database re-read
LC43 Jul 5, 2026
38b973b
fix(export): inspect WP_Query vars instead of compiled SQL
LC43 Jul 5, 2026
7df4947
fix(audit): set explicit UTC timezone in DateTimeImmutable
LC43 Jul 5, 2026
603a1a2
docs: update changelog after code review round 2
LC43 Jul 5, 2026
ec4b447
fix(mcp): resolve post type capability dynamically for get_settings, …
LC43 Jul 5, 2026
7781be5
fix(meta): add switcher boolean type to schema type map
LC43 Jul 5, 2026
db886d5
docs: log completed code review round 3 work in CURRENT.md
LC43 Jul 5, 2026
477778a
fix(rest): Use check_method helper for safe model property access
LC43 Jul 5, 2026
b6309ca
fix(mcp): Register cache-clear hooks for option add/delete events
LC43 Jul 5, 2026
181a562
fix(settings): Preserve key casing in settings sanitization
LC43 Jul 5, 2026
79b4270
fix(audit): Use MySQL-compatible datetime format in audit trail
LC43 Jul 5, 2026
8f881bd
Remove extra clean up call
LC43 Jul 5, 2026
2cac491
fix(container): Add instantiate_unconditionally() to bypass Condition…
LC43 Jul 6, 2026
71ad7e0
fix(core): Register RestRouteProvider ToolContributor before is_neede…
LC43 Jul 6, 2026
2a32ea3
feat(infra): Create FilterAwareTrait for WordPress filter helpers
LC43 Jul 6, 2026
c103adc
refactor(mcp): Use FilterAwareTrait in AbilityRuntime
LC43 Jul 6, 2026
0f9db96
refactor(mcp): Use FilterAwareTrait in AuditLogger
LC43 Jul 6, 2026
c4dc432
refactor(mcp): Use FilterAwareTrait in TransientCache
LC43 Jul 6, 2026
2d047ef
refactor(mcp): Use FilterAwareTrait in RateLimiter HealthController
LC43 Jul 6, 2026
102cef2
feat(mcp): Add prepare method to AuditDatabase interface
LC43 Jul 6, 2026
9c37add
feat(mcp): Add is_list helper to Validator for type checks
LC43 Jul 6, 2026
65ca35a
fix(rest): Remove permissive permission check in DuplicateController
LC43 Jul 6, 2026
5bea515
fix(rest): Add model policy checks to SettingsController permissions
LC43 Jul 6, 2026
616c54a
fix(settings): Improve update_post_settings unchanged detection
LC43 Jul 6, 2026
8d236b8
fix(test): Use wpdb prepare quoting in export_wp helper revert to echo
LC43 Jul 6, 2026
5c367e2
fix(test): Update audit logger test assertions for prepared SQL
LC43 Jul 6, 2026
a271777
test: Add covers annotations to Unit Container tests
LC43 Jul 6, 2026
a7ccc8c
test: Add covers annotations to AssetDataTest
LC43 Jul 6, 2026
479b73b
test: Add covers annotations to Modeler tests
LC43 Jul 6, 2026
34b7557
test: Add covers annotations to Unit Model tests
LC43 Jul 6, 2026
412b1ee
test: Add covers annotations to Feature Integration tests
LC43 Jul 6, 2026
2174c38
test: Add covers annotations to MCP Ability Audit tests
LC43 Jul 6, 2026
ab8d207
test: Add covers annotations to MCP Cache RateLimiter tests
LC43 Jul 6, 2026
02fe6da
test: Add covers annotations to MCP Tools Validation tests
LC43 Jul 6, 2026
3aa8667
test: Add covers annotations to Rest Controller tests
LC43 Jul 6, 2026
dfbcf44
test: Add covers annotations to remaining Rest tests
LC43 Jul 6, 2026
96a1906
docs: Update README CONTEXT for MCP routing conditional registration
LC43 Jul 6, 2026
5b79fb7
docs: Update CURRENT MCP docs for completed MCP routing changes
LC43 Jul 6, 2026
df3306b
docs: Update ROADMAP CURRENT for conditional registration fix FilterA…
LC43 Jul 6, 2026
1dc156d
Fix return type in docs
LC43 Jul 6, 2026
035c1e7
CS
LC43 Jul 6, 2026
c36673d
CS
LC43 Jul 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 26 additions & 138 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,162 +1,50 @@
name: CI

on:
workflow_dispatch:
push:
branches:
- main
tags:
- "v*"
branches: [main, feature/**]
pull_request:
branches:
- main
schedule:
- cron: "23 4 * * 1"

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
branches: [main]

jobs:
composer:
name: Composer validation
test:
name: PHP ${{ matrix.php }} — tests
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: ['7.4', '8.0', '8.1', '8.2', '8.3']

steps:
- name: Checkout
uses: actions/checkout@v7
- uses: actions/checkout@v4

- name: Setup PHP
- name: Set up PHP ${{ matrix.php }}
uses: shivammathur/setup-php@v2
with:
php-version: "8.3"
coverage: none
php-version: ${{ matrix.php }}
tools: composer:v2
coverage: none

- name: Validate Composer package
- name: Validate composer.json
run: composer validate --strict

composer-audit:
name: Composer audit
runs-on: ubuntu-latest
needs: composer

steps:
- name: Checkout
uses: actions/checkout@v7

- name: Setup PHP with Composer cache
uses: ./.github/actions/php-setup
- name: Cache Composer dependencies
uses: actions/cache@v4
with:
cache-key: ${{ runner.os }}-audit-php8.3-composer-${{ hashFiles('composer.lock') }}
cache-restore-keys: ${{ runner.os }}-audit-php8.3-composer-
path: vendor
key: composer-${{ runner.os }}-${{ matrix.php }}-${{ hashFiles('composer.json') }}
restore-keys: |
composer-${{ runner.os }}-${{ matrix.php }}-
composer-${{ runner.os }}-

- name: Install dependencies
run: composer install --no-ansi --no-interaction --no-progress --prefer-dist
run: composer install --prefer-dist --no-progress

- name: Run Composer audit
run: composer audit

coding-standards:
name: Coding standards and PHP compatibility
runs-on: ubuntu-latest
needs: composer

steps:
- name: Checkout
uses: actions/checkout@v7

- name: Setup PHP with Composer cache
uses: ./.github/actions/php-setup
with:
cache-key: ${{ runner.os }}-phpcs-php8.3-composer-${{ hashFiles('composer.lock') }}
cache-restore-keys: ${{ runner.os }}-phpcs-php8.3-composer-

- name: Install dependencies
run: composer install --no-ansi --no-interaction --no-progress --prefer-dist

- name: Run PHPCS
run: composer phpcs

static-analysis:
name: Static analysis
runs-on: ubuntu-latest
needs: composer

steps:
- name: Checkout
uses: actions/checkout@v7

- name: Setup PHP with Composer cache
uses: ./.github/actions/php-setup
with:
cache-key: ${{ runner.os }}-phpstan-php8.3-composer-${{ hashFiles('composer.lock') }}
cache-restore-keys: ${{ runner.os }}-phpstan-php8.3-composer-

- name: Install dependencies
run: composer install --no-ansi --no-interaction --no-progress --prefer-dist
- name: Run PHPUnit
run: ./vendor/bin/phpunit -c phpunit.xml

- name: Run PHPStan
run: composer phpstan -- --no-progress

dependency-compatibility:
name: PHP ${{ matrix.php }} / ${{ matrix.dependencies }} runtime dependencies
runs-on: ubuntu-latest
needs: composer

strategy:
fail-fast: false
matrix:
php:
- "7.4"
- "8.0"
- "8.1"
- "8.2"
- "8.3"
- "8.4"
dependencies:
- highest
include:
- php: "7.4"
dependencies: lowest
- php: "8.3"
dependencies: locked
- php: "8.4"
dependencies: locked
run: ./vendor/bin/phpstan analyse --memory-limit=2G --no-progress

steps:
- name: Checkout
uses: actions/checkout@v7

- name: Setup PHP with Composer cache
uses: ./.github/actions/php-setup
with:
php-version: ${{ matrix.php }}
cache-key: ${{ runner.os }}-dependencies-php${{ matrix.php }}-${{ matrix.dependencies }}-${{ hashFiles('composer.json', 'composer.lock') }}
cache-restore-keys: |
${{ runner.os }}-dependencies-php${{ matrix.php }}-${{ matrix.dependencies }}-
${{ runner.os }}-dependencies-php${{ matrix.php }}-

- name: Prepare runtime-only Composer manifest
run: jq 'del(."require-dev", ."autoload-dev", .scripts)' composer.json > composer.runtime.json

- name: Install locked dependencies
if: matrix.dependencies == 'locked'
run: composer install --no-dev --no-ansi --no-interaction --no-progress --prefer-dist

- name: Install highest dependencies
if: matrix.dependencies == 'highest'
run: COMPOSER=composer.runtime.json composer update --no-dev --no-ansi --no-interaction --no-progress --prefer-dist

- name: Install lowest dependencies
if: matrix.dependencies == 'lowest'
run: COMPOSER=composer.runtime.json composer update --no-dev --prefer-lowest --prefer-stable --no-ansi --no-interaction --no-progress --prefer-dist

- name: Validate Composer platform compatibility
run: composer check-platform-reqs --no-dev

- name: Lint PHP source
run: find src -name '*.php' -print0 | xargs -0 -n 1 -P 4 php -l
- name: Run PHPCS
run: ./vendor/bin/phpcs --standard=phpcs.xml
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ vendor/
**/.DS_Store
.vscode
*~
saltus-framework.code-workspace
saltus-framework.code-workspace
tests/tester.php
56 changes: 53 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,59 @@


## [Unreleased]
- Fix: Bring the source tree back to a clean PHPStan level 7 run.
- Improvement: Tighten service, model, asset, admin column, admin filter, and meta feature typing.
- Docs: Document local static-analysis and coding-standard checks.

### Fixed
- Fixed single-post REST export so `/saltus-framework/v1/export/{post_id}` returns WXR for only the requested post instead of the entire post type.
- Fixed framework lifecycle hook registration by allowing `Core` to receive the consuming plugin bootstrap file for activation/deactivation hooks.
- Tightened WordPress-native MCP/Abilities permission callbacks so mutating post and term tools fail closed when required target arguments are missing.
- Fixed structured settings updates so nested arrays, booleans, numbers, and null values are preserved while string values and keys are sanitized recursively.
- Fixed settings sanitization so non-stringable object payloads cannot fatal during REST/MCP settings updates.
- Fixed single-post REST export so WordPress core download headers from `export_wp()` do not leak into REST responses.
- Fixed health error-rate reporting so validation and rate-limit outcomes remain visible but do not mark framework health as degraded.
- Fixed the non-WordPress JSON encoding fallback in `AbilityRuntime`.
- Cleared the remaining PHPStan Level 7 issues in `Modeler`, REST route registration, and MCP taxonomy REST-base handling.
- Added an explicit model name accessor contract so `Modeler` no longer depends on concrete model properties.

### Changed
- Added regression coverage for export isolation, plugin-file lifecycle hook registration, fail-closed MCP ability permissions, and structured settings payloads.
- Brought `AssetLoader` back under PHPStan analysis with a typed `AssetLoadingService` base class.
- Removed the standalone stdio MCP server path; WP7 MCP/Abilities is now the only supported MCP transport.
- Migrated MCP audit logging, rate limiting, and caching to WordPress-native storage around WP7 ability execution.
- Moved MCP audit retention cleanup from the audit write path to a daily WP-Cron event.

## [2.0.0] - 2026-06-30

### Added
- MCP/Abilities integration: WordPress 7.0 native ability definitions through AbilityRegistrar
- MCP protocol server with stdio transport: initialize, tools/list, tools/call, resources/list, resources/read, prompts/list, prompts/get
- REST API namespace `saltus-framework/v1/` with 9 routes: models, duplicate, export, settings (GET/PUT), meta (aggregate + per-CPT), reorder
- 16 MCP tools (9 Phase 1 CRUD + 7 Phase 2): models, posts, terms, duplicate, export, settings, reorder, meta fields
- 3 MCP prompt templates for post/content generation workflows
- Meta field normalization: nested Codestar fields flattened to explicit paths with JSON-schema-like types
- ToolFactory for shared tool definitions between MCP and WordPress-native abilities
- Caching layer (CacheInterface + InMemoryCache) for WordPressClient GET requests
- Sliding-window rate limiter (default 60 req/60s) for tool calls
- Audit trail logger with JSON records to STDERR and optional file
- Structured error codes (ErrorCode constants + McpError value object with resolution hints)
- Config::fromEnv for environment-variable-based configuration (15 env vars)
- 243 PHPUnit tests across MCP, REST, and framework core

### Fixed
- Rate limiter race condition in concurrent test scenarios
- ModelFactory static make method call operator
- WalkerTaxonomyDropdown incompatible void return type
- WordPress key length validation in get_registration_name()
- Admin columns non-string return from get_edit_term_link
- Various type safety issues across services, models, assets, admin columns, meta, drag-drop, and container

### Changed
- Version bumped to 2.0.0
- Type safety improvements across the entire codebase
- MCP Server uses ToolFactory for unified tool definitions
- Config constructor refactored to array bag pattern
- PHP 8.3+ required (str_starts_with in McpError)
- PHPStan Level 7 compliance for all src/MCP/ and src/Rest/ code
- PHPUnit configuration with strict flags, random execution order, and failOn* rules

## [1.3.5] - 2026-06-20
- Chore: Package it for packagist
Expand Down
84 changes: 82 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Visit saltus.dev for more information.

## Version

### Current version [1.3.5] - 2026-06-20
### Current version [2.0.0] - 2026-06-30

See [change log file](CHANGELOG.md) for full details.

Expand Down Expand Up @@ -59,7 +59,7 @@ Once the framework is installed and Composer's autoloader is loaded by your plug
* The path to the plugin root directory is mandatory,
* so it loads the models from a subdirectory.
*/
$framework = new \Saltus\WP\Framework\Core( dirname( __FILE__ ) );
$framework = new \Saltus\WP\Framework\Core( dirname( __FILE__ ), __FILE__ );
$framework->register();

/**
Expand Down Expand Up @@ -183,6 +183,86 @@ Includes support for [github-updater](https://github.com/afragen/github-updater)
* Clone [github-updater](https://github.com/afragen/github-updater) to your sites plugins/ folder
* Activate via WordPress

## WordPress-Native MCP/Abilities

Saltus Framework exposes its AI-facing tool surface through the WordPress-native MCP/Abilities API. Native WordPress MCP clients can discover and call the `saltus/*` abilities directly from the active plugin.

For full documentation, see [docs/MCP.md](docs/MCP.md). For client integration guidance, see [docs/MCP-CLIENTS.md](docs/MCP-CLIENTS.md). These pages are source material for the future Saltus MCP documentation site.

### Quick Start

Install and activate the plugin that uses Saltus Framework on a WordPress version with the Abilities API. Saltus registers its abilities during `wp_abilities_api_init`; clients that understand WordPress-native MCP/Abilities can discover the `saltus/*` tools from WordPress.

The standalone local stdio MCP server has been removed. Saltus MCP development targets WordPress-native abilities instead.

### Capability Dispatch

Abilities dispatch through WordPress REST requests, so existing REST permission callbacks and `current_user_can()` checks remain authoritative. WordPress versions without the Abilities API simply skip Saltus ability registration.

### Service Gating and `is_needed()`

To keep the application performant and clean, the framework separates REST/MCP route registration from the execution of admin and frontend hooks using a two-pass registration model:
- **First Pass (Unconditional):** Services implementing `RestRouteProvider` or `ToolContributor` are instantiated unconditionally during plugin boot to register endpoints and tools. No scripts, styles, or hooks are wired up.
- **Second Pass (Gated):** Services are registered in the main service container, which strictly enforces the `is_needed()` gate (defined by the `Conditional` interface). If `is_needed()` returns `false` (e.g. an admin-only feature on a frontend page, or a disabled feature), the service is skipped, avoiding loading unneeded scripts, styles, or hooks.

Saltus wraps ability execution with WordPress-native audit logging, rate limiting, and transient caching. Read-only abilities can be cached in transients, mutating abilities clear the MCP cache, rate limits are keyed by the current user or request identifier, and audit records are written to the Saltus MCP audit table. Expired audit rows are removed by a daily WP-Cron retention job.

### Available Tools

| Tool | Description |
|------|-------------|
| `get_health` | Get Saltus Framework health, version, error rate, latency, cache, and rate-limit status |
| `list_models` | List all registered CPTs and taxonomies |
| `get_model` | Get details of a specific post type or taxonomy |
| `list_posts` | Query posts with filters (status, search, pagination) |
| `get_post` | Get a single post with all fields and meta |
| `create_post` | Create a new post in any CPT |
| `update_post` | Update an existing post's fields and meta |
| `delete_post` | Trash or force delete a post |
| `list_terms` | List terms from a taxonomy |
| `create_term` | Create a new term in a taxonomy |
| `duplicate_post` | Duplicate a WordPress post |
| `export_post` | Export a post as WXR |
| `get_settings` | Get Saltus settings for a post type |
| `update_settings` | Update Saltus settings for a post type |
| `reorder_posts` | Batch update post menu order |
| `list_meta_fields` | Discover Saltus meta field definitions across all registered CPTs |
| `get_meta_fields` | Get Saltus meta field definitions for a post type |

Meta field discovery preserves the raw Saltus/Codestar configuration in `meta` and includes normalized MCP-friendly metadata in `normalized.fields` and `normalized.rest_meta_keys`. Nested fields are exposed as paths such as `points_info.coordinates.latitude`, with JSON-schema-like types and REST writability information.

### Requirements

- WordPress 7.0+ or a WordPress build that provides the Abilities API
- A WordPress-native MCP/Abilities client
- The plugin using Saltus Framework must be active

### Configuration

No local MCP server configuration is required for the WordPress-native path. Runtime behavior can be tuned with WordPress filters:

| Filter | Purpose |
|--------|---------|
| `saltus/framework/mcp/audit/enabled` | Enable or disable audit writes |
| `saltus/framework/mcp/audit/retention_days` | Set audit retention before daily WP-Cron cleanup |
| `saltus/framework/mcp/rate_limit/enabled` | Enable or disable rate limiting |
| `saltus/framework/mcp/rate_limit/max_requests` | Set max ability calls per window |
| `saltus/framework/mcp/rate_limit/window_seconds` | Set the rate-limit window |
| `saltus/framework/mcp/rate_limit/identifier` | Override the rate-limit identifier |
| `saltus/framework/mcp/cache/enabled` | Enable or disable transient caching |
| `saltus/framework/mcp/cache/ttl` | Set cache TTL per tool |
| `saltus/framework/mcp/cache/cacheable` | Override whether a tool is cacheable |

### Generated MCP documentation

The detailed MCP ability reference is generated from the `src/MCP/Tools` source classes:

```bash
composer docs:mcp
```

This refreshes `docs/MCP-ABILITIES.md` and the generated ability table in `docs/MCP.md`.

## Building

### Quality checks
Expand Down
Loading
Loading