Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
15f722f
build: exclude phpstan-bootstrap.php from the plugin zip
zackkatz Jun 15, 2026
3c03c42
ci(release): stop GitHub Actions from creating the version tag/release
zackkatz Jun 15, 2026
01246d0
fix(yoast): advertise noindex as a single boolean type, not [boolean,…
dallinchase Jun 14, 2026
6770df1
fix(yoast): attribute the scalar-type constraint to Gemini; rebuild b…
zackkatz Jun 16, 2026
c6683dd
chore(deps): patch npm security advisories and bump server to 2.0.2
zackkatz Jun 17, 2026
27720c8
fix(settings): keep block-preference defaults and persist the first save
zackkatz Jun 17, 2026
f2b2115
Merge main into develop: reconcile delete-by-ref hotfix
zackkatz Jun 17, 2026
e34d0a7
test(settings): cover preference layering, sanitize idempotency, and …
zackkatz Jun 17, 2026
dcd6a7d
chore(review): address CodeRabbit feedback on the settings PR
zackkatz Jun 17, 2026
03cd3ba
Merge pull request #32 from GravityKit/chore/dependabot-security-bumps
zackkatz Jun 17, 2026
31b8b60
Merge remote-tracking branch 'origin/develop' into fix/settings-prefe…
zackkatz Jun 17, 2026
1fc841d
docs(changelog): split the Add row affordance (Improved) from the sil…
zackkatz Jun 17, 2026
f2afb5b
Merge pull request #33 from GravityKit/fix/settings-preference-data-loss
zackkatz Jun 17, 2026
91e8a6f
chore(release): Block MCP 2.0.3
zackkatz Jun 17, 2026
ce7f2e8
docs(agents): reconcile release/@since guidance; fix Yoast test-comme…
zackkatz Jun 17, 2026
b39fba3
feat(preferences): make block preferences site-aware and opinion-free
zackkatz Jun 18, 2026
c85b666
test(preferences): cover site-aware model, migration, and orphaned bl…
zackkatz Jun 18, 2026
a7d2bec
docs(changelog): document site-aware block preferences [ci skip]
zackkatz Jun 18, 2026
1f1e346
fix(write): freshen post cache before read-modify-write to prevent lo…
zackkatz Jun 23, 2026
810f5fc
fix(write): always-on optimistic-concurrency CAS so writes fail close…
zackkatz Jun 23, 2026
ca87b5a
fix(write): harden CAS per review — byte-exact ref-persist, fresh-sta…
zackkatz Jun 23, 2026
c1fde65
feat(abilities): register Block MCP operations as WordPress 6.9 Abili…
zackkatz Jun 23, 2026
a42227e
fix(security): strip block-comment delimiters from innerHTML on every…
zackkatz Jun 23, 2026
8a78c83
feat(abilities): add delete-block + site-editor-context abilities, wi…
zackkatz Jun 23, 2026
cae3def
feat(abilities): add Settings toggle for Abilities registration (defa…
zackkatz Jun 23, 2026
905f2ae
fix(abilities): declare explicit destructive annotations on update/in…
zackkatz Jun 23, 2026
13ea365
test(rest): dispatch the stale-cache lost-update suite through the re…
zackkatz Jun 23, 2026
51148cf
fix(write): close the verify-to-write race in save_post_content with …
zackkatz Jun 23, 2026
2fd8777
Merge pull request #36 from GravityKit/fix/block-write-stale-cache-lo…
zackkatz Jun 23, 2026
ea1864a
Merge remote-tracking branch 'origin/develop' into feature/block-22-r…
zackkatz Jun 23, 2026
d6583fa
Merge pull request #37 from GravityKit/feature/block-22-register-bloc…
zackkatz Jun 23, 2026
c2efbd9
Merge develop into tweak/improve-preferences
zackkatz Jun 23, 2026
44c05eb
fix(write): correct idempotent-save + DB-error handling in the CAS, a…
zackkatz Jun 23, 2026
3be8870
Merge pull request #35 from GravityKit/tweak/improve-preferences
zackkatz Jun 23, 2026
223adcf
fix(settings): address non-technical-admin UX findings from user testing
zackkatz Jun 23, 2026
5f96d2f
fix(settings): give replacement-map new/added rows a Remove button
zackkatz Jun 23, 2026
a9a7319
fix(settings): harden allow-all uncheck-to-zero and tier badge on reset
zackkatz Jun 23, 2026
8ea7d2b
fix(block-mcp): resolve query-string permalinks instead of the front …
zackkatz Jun 26, 2026
e0157b9
Fix the detection of disabled Application Passwords & explain how to …
mrcasual Jul 1, 2026
f5865a8
Merge pull request #38 from GravityKit/tweak/settings-ux-sarah
zackkatz Jul 6, 2026
c16133d
fix(write): pluggable normalization framework, repair invalid block m…
zackkatz Jun 23, 2026
9488bb3
fix(mutator): keep moved blocks inside the destination wrapper's markup
zackkatz Jul 6, 2026
f011e2a
fix(write): echo persisted (normalized) blocks in saved snapshots; re…
zackkatz Jul 6, 2026
ec8f1dd
Merge pull request #40 from GravityKit/fix/mutator-move-placeholder
zackkatz Jul 6, 2026
8023221
Merge remote-tracking branch 'origin/develop' into fix/block-conformance
zackkatz Jul 6, 2026
85f4cac
Merge pull request #39 from GravityKit/fix/block-conformance
zackkatz Jul 6, 2026
0317710
fix(security): stop agent role gaining edit_theme_options; restore tr…
zackkatz Jul 6, 2026
77cdfc1
fix(transform): keep the <code> wrapper when updating a core/code blo…
zackkatz Jul 6, 2026
fba2cff
fix(mcp): list_patterns reports true total + working next_offset
zackkatz Jul 6, 2026
7a7701e
fix(security): disable HTTP redirects on URL media sideload (SSRF)
zackkatz Jul 6, 2026
6d25a96
fix(mcp): accept numeric-string post_id consistently; guard get_block…
zackkatz Jul 6, 2026
8d6f329
test(abilities): pin the MCP Adapter contract
zackkatz Jul 6, 2026
c5d1eb9
docs(changelog): fix subject/verb agreement (leave → leaves) [ci skip]
zackkatz Jul 6, 2026
8f41afd
fix(coerce): reject zero-valued post_id strings like the number 0
zackkatz Jul 6, 2026
713ae62
Merge pull request #46 from GravityKit/test/mcp-adapter-hardening
zackkatz Jul 6, 2026
30fc47b
Merge pull request #44 from GravityKit/fix/ssrf-redirect-revalidation
zackkatz Jul 6, 2026
84e1585
Merge pull request #42 from GravityKit/fix/core-code-content-transform
zackkatz Jul 6, 2026
cadfe69
Merge pull request #43 from GravityKit/fix/list-patterns-pagination
zackkatz Jul 6, 2026
a46d675
Merge remote-tracking branch 'origin/develop' into fix/agent-privileg…
zackkatz Jul 6, 2026
d3884eb
Merge remote-tracking branch 'origin/develop' into fix/ts-input-coercion
zackkatz Jul 6, 2026
0235f55
Merge pull request #41 from GravityKit/fix/agent-privilege-and-option…
zackkatz Jul 6, 2026
a73db41
Merge pull request #45 from GravityKit/fix/ts-input-coercion
zackkatz Jul 6, 2026
ef328b4
docs(changelog): customer-focused security entries; add release summa…
zackkatz Jul 6, 2026
8104569
fix(security): strip forbidden caps from an existing agent role on up…
zackkatz Jul 6, 2026
ebec2e3
test: align array operators in remediation test [ci skip]
zackkatz Jul 6, 2026
fcd096c
Merge pull request #47 from GravityKit/fix/agent-role-remediate-forbi…
zackkatz Jul 6, 2026
9d17fb6
release: bump plugin to 2.1.0
zackkatz Jul 6, 2026
0b6372f
fix(transformer): strip empty class only from real tags, not text
zackkatz Jul 8, 2026
81f966b
Merge fix/strip-empty-class-text-corruption into develop
zackkatz Jul 8, 2026
cceb7f8
fix(post-manager): drop orphaned innerContent nulls on create_post
zackkatz Jul 8, 2026
54d69ac
test(stress): add permanent move-inclusive mutation-chaos walk
zackkatz Jul 8, 2026
e6703d5
test(stress): randomize move-chaos seeds per run, keep reproducible
zackkatz Jul 8, 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
60 changes: 0 additions & 60 deletions .github/workflows/build-plugin-zip.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,66 +106,6 @@ jobs:
prerelease: true
files: gk-block-mcp.zip

# Merging a plugin version bump to main IS the release: when the plugin
# Version header has no v{version} tag yet, create the tag + GitHub
# release here, with the version's readme.txt Changelog entry as the body
# and the ZIP attached. This must happen in this job rather than via a separate
# tag push — tags pushed with GITHUB_TOKEN don't trigger other
# workflows, so a tag-push hop would never fire the release build.
# The npm publish workflow keys off package.json independently (the
# plugin and the MCP server version separately); both fire from the
# same merge, keeping GitHub and npm releases in sync.
- name: Detect an unreleased plugin version (push to main)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
id: plugin_version
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
VERSION="$(sed -n 's/^ \* Version: //p' wordpress-plugin/gk-block-mcp/gk-block-mcp.php | head -1 | tr -d '[:space:]')"
if [ -z "$VERSION" ]; then
echo "::error::Could not read the plugin Version header."
exit 1
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
if gh api "repos/${GITHUB_REPOSITORY}/git/ref/tags/v$VERSION" >/dev/null 2>&1; then
echo "unreleased=false" >> "$GITHUB_OUTPUT"
echo "v$VERSION is already tagged — nothing to release."
exit 0
fi
# A '= develop =' changelog header means the readme was never
# finalized for this release — refuse to ship it.
if grep -q '^= develop =' wordpress-plugin/gk-block-mcp/readme.txt; then
echo "::error::readme.txt still contains a '= develop =' placeholder — finalize the changelog before releasing v$VERSION."
exit 1
fi
echo "unreleased=true" >> "$GITHUB_OUTPUT"
# Release body = the version's Changelog entry from readme.txt
# (its header is "= X.Y.Z on {DATE} =" — match the version + " on ").
awk -v ver="= $VERSION on " '
index($0, ver) == 1 { grab = 1; next }
grab && /^= / { exit }
grab { print }
' wordpress-plugin/gk-block-mcp/readme.txt > "$RUNNER_TEMP/release-notes.md"
if ! grep -q '[^[:space:]]' "$RUNNER_TEMP/release-notes.md"; then
echo "::warning::No changelog entry found for $VERSION in readme.txt — using a generic body."
printf 'Release v%s. See readme.txt for the changelog.\n' "$VERSION" > "$RUNNER_TEMP/release-notes.md"
fi

- name: Create tag + release for the new version (push to main)
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && steps.plugin_version.outputs.unreleased == 'true'
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.plugin_version.outputs.version }}
run: |
set -euo pipefail
# --target pins the tag to the exact commit this ZIP was built from.
gh release create "v$VERSION" gk-block-mcp.zip \
--target "$GITHUB_SHA" \
--title "v$VERSION" \
--notes-file "$RUNNER_TEMP/release-notes.md"

# Backstop: a manually pushed v* tag still publishes a release.
- name: Tagged release
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ docs/screenshots/
# Connect-doc e2e output (regenerated by `npm run test:docs`).
tests/docs/screenshots/
tests/docs/.playwright-artifacts/

# Settings-UI regression e2e output (regenerated by `npm run test:e2e`).
tests/e2e/.playwright-artifacts/
13 changes: 7 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ MCPs/block-mcp/
└── wordpress-plugin/gk-block-mcp/
├── gk-block-mcp.php # Bootstrap: autoloader, rest_api_init wiring, admin wiring, CLI
├── uninstall.php # Full data + agent teardown (multisite-aware)
├── readme.txt # Canonical changelog + Upgrade Notice (WordPress plugin readme)
├── readme.txt # Canonical changelog (WordPress plugin readme)
├── phpcs.xml.dist # WordPress-Extra + WordPress-Docs + PHPCompatibilityWP (testVersion 7.4-)
├── phpstan.neon.dist # PHPStan level 5, analyze-as-PHP-8.2, WP stubs
├── phpstan-bootstrap.php # Placeholder constants for static analysis
Expand Down Expand Up @@ -168,7 +168,7 @@ Write them as standalone documentation of what the code does **today** — never
Don't name specific third-party block namespaces as "legacy" in comments, error messages, REST responses, or changelog text — the legacy tier is site-configurable via `Preferences`. Use generic phrasing ("the namespace is configured as legacy"). Test *fixtures* may use a concrete namespace, but resolve it from `Preferences::get_defaults()` at runtime rather than hardcoding.

### Version annotations
`@since {version}` for released members; update `@since` when adding members. New connect/identity code uses `@since 2.1.0` as a placeholder until the release version is settled.
`@since {version}` annotates **shipped public members** — production classes, methods, hooks, and REST routes. Update `@since` when adding such a member; new code uses `@since 2.1.0` as a placeholder until the release version is settled. **Test files (`tests/**`) do not carry `@since`** — they pin contracts, not API surface, and the suite is uniformly free of it.

## Extension Patterns

Expand Down Expand Up @@ -221,17 +221,18 @@ The plugin and MCP server version independently. The plugin follows WP plugin co

**Semver (plugin):** MAJOR = breaking REST/tool changes; MINOR = additive endpoints/tools/fields/settings; PATCH = fixes/hardening/refactors/i18n/tests.

**Every plugin version bump updates all five:**
**Every plugin version bump updates all four:**
1. `gk-block-mcp.php` `* Version:` header
2. `gk-block-mcp.php` `GK_BLOCK_MCP_VERSION` constant
3. `readme.txt` `Stable tag:`
4. `readme.txt` `== Upgrade Notice ==` (1–3 sentences, headline value, newest at top — this is what the WP update screen shows)
5. `readme.txt` `== Changelog ==` (grouped `New`/`Improved`/`Fixed`/etc., newest at top)
4. `readme.txt` `== Changelog ==` (a `= {version} on {date} =` entry with a one-sentence summary, grouped `Added`/`Improved`/`Fixed`/`Updated`, newest at top)

**No `== Upgrade Notice ==` section.** GravityKit plugins update through Foundation, not the WP.org directory, so it is never surfaced to users; the GitHub release notes are sourced from the Changelog entry instead. `readme.txt` ends at `== Changelog ==`.

**MCP server bump:** `package.json` `version` (+ optional readme mention if a TS change is user-observable).

**Releasing = merging the version bump to `main`.** Two workflows fire from the merge and keep GitHub and npm in sync:
- `build-plugin-zip.yml` reads the plugin `Version` header; when no `v{plugin-version}` tag exists yet it creates the tag + GitHub release (body = that version's `readme.txt` Upgrade Notice, `gk-block-mcp.zip` attached). A manually pushed `v*` tag still publishes a release as a backstop — note a workflow-created tag does NOT re-trigger workflows (`GITHUB_TOKEN` events don't cascade), which is why the release is created in the build job rather than via a tag push.
- `build-plugin-zip.yml` reads the plugin `Version` header; when no `v{plugin-version}` tag exists yet it creates the tag + GitHub release (body = that version's `readme.txt` Changelog entry, `gk-block-mcp.zip` attached). A manually pushed `v*` tag still publishes a release as a backstop — note a workflow-created tag does NOT re-trigger workflows (`GITHUB_TOKEN` events don't cascade), which is why the release is created in the build job rather than via a tag push.
- `npm-publish.yml` publishes `@gravitykit/block-mcp` (npm Trusted Publishing/OIDC, no token secret) whenever the `package.json` version isn't on the registry yet — independent of the plugin tag, since the two version separately.

On feature branches, the changelog header is `= develop =` until release.
Expand Down
Loading
Loading