Commit Graph
53 Commits
Author SHA1 Message Date
Jan-Niclas Loosen 3337a63c5d Prepare auto updates 2026-11-04 13:51:01 +01:00
Jan-Niclas LoosenandClaude Sonnet 5.5 b91c356a28 chore: Version 0.7.0 (Etappe 4); Spec und Notizen nachgeführt
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 00:31:24 +02:00
Jan-Niclas LoosenandClaude Sonnet 5.5 2aef6e1154 feat: lit-site-status, Admin-Tab und Admin-Hinweis zeigen Divi-Fähigkeiten mit Zustand, Quelle, Problemen und betroffenen Werkzeugen
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 22:29:38 +02:00
Jan-Niclas LoosenandClaude Sonnet 5.5 74cf0c54a8 feat: DiviFeatureGate ersetzt DiviToolGate – Ablehnung je Fähigkeit für Lese- und Schreib-Tools, Details nach D6, kein Hinweis mehr in warnings; DiviContentComposer::refusal prüft seine Fähigkeiten
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 22:18:39 +02:00
Jan-Niclas LoosenandClaude Opus 5.5 e6e0f914ba refactor: ToolAvailability ersetzt die sechs Referenz-Closures in Plugin (Frage vor der Verdrahtung wirft statt still false); DiviIntegration bekommt den Tools-Tab-Zustand als Objekt; Plugin::integrations() mit Verdrahtungstest für Reihenfolge, einmaliges Booten und spätes Binden
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 21:56:36 +02:00
Jan-Niclas LoosenandClaude Opus 5.5 6c59934caa refactor: Divi-Boot-Schritte in DiviIntegration::boot() (Bootable) – Upgrader-Hook, Prüf-Route, CLI und Reiter „Divi“ über lit_mcp_admin_tabs; IntegrationRegistry::boot() bootet jede Integration genau einmal; Prüfseiten-Aufräumen im load-Hook statt beim Rendern
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 21:53:04 +02:00
Jan-Niclas LoosenandClaude Sonnet 5.5 06148fb8c1 refactor: Kern ohne Divi – Ports BuilderDetector, MediaUsageSource, EnvironmentComponent und ausgeschlossene Post-Typen im ContentSchema; Divi-Implementierungen und Verdrahtung über DiviIntegration/Plugin; CoreIndependenceTest
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 21:49:28 +02:00
Jan-Niclas LoosenandClaude Sonnet 5.5 abeb4b0eed refactor: AbilityRegistrar nimmt AbilityGuard-Liste und ToolRefusal statt DiviToolGate/DiviLocked; DiviToolGate implementiert AbilityGuard, DiviLocked ToolRefusal; Test mit Fake-Guard und Fake-Refusal ohne Divi
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 21:47:26 +02:00
Jan-Niclas LoosenandClaude Fable 5.1 e5f0c65eb0 feat: Divi 5.14.0 freigeben, Version 0.6.1
Divi 5.14.0 ändert SyncToServerController::update(): Vorlieben und
Workspace werden nicht mehr dort gespeichert, der Haupt-Post nur noch
bei singulären Builder-Speicherungen geschrieben. Die drei nachgebauten
Builder-Kennzeichen (_et_pb_use_divi_5, _et_pb_use_builder,
_et_pb_show_page_creation) werden unverändert gesetzt – Referenz und
Fingerabdruck per `wp lit-mcp divi-check --update-reference` nachgezogen,
Prüfung und divi-write-smoke.sh gegen 5.14.0 grün. 5.14.0 steht damit in
DiviReleases::TESTED.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-08 16:58:34 +02:00
janniclas.loosenandClaude Opus 5.5 35ea47d832 chore: release 0.6.0 with Divi release gate, smoke test and acceptance notes
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 03:19:31 +02:00
janniclas.loosenandClaude Opus 5.5 ed806a1cc8 feat: wp lit-mcp divi-check with diff and reference update
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 02:52:17 +02:00
janniclas.loosenandClaude Opus 5.5 6113e5ad5a feat: Divi tab with REST check, release and withdrawal
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 02:39:21 +02:00
janniclas.loosenandClaude Opus 5.5 c6a1996be6 feat: adapter-level Divi release lock, content-create and site status
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 02:04:49 +02:00
janniclas.loosenandClaude Opus 5.5 adfe0adfc2 feat: central Divi release lock for the Divi tools
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 01:54:36 +02:00
janniclas.loosenandClaude Opus 5.5 3db96a3f5b docs: Theme Builder guide, instructions, readme and spec for 0.5.0
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 22:05:33 +02:00
janniclas.loosenandClaude Opus 5.5 54922a9f7e feat: lit/tb-list and the tool group "Divi Theme Builder"
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 15:57:45 +02:00
janniclas.loosenandClaude Opus 5.5 b1dd35abd8 feat: Divi tools edit Theme Builder layouts; visible layouts need confirm
TB layouts load through ThemeBuilderAccess (P12), live layouts (attached +
enabled, Q8) need a dry run and confirm (Q9) and get the shared restore point
of VisibleEdits, extracted from GlobalEdits (Q2: backup when revisions are
off, P9 refusals, P14 naming). divi/post-content only in body layouts (F22),
also for nested stored nodes. SaveScope::ThemeBuilderLayout sets Divi flags
and clears site CSS + TB cache.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 15:45:07 +02:00
janniclas.loosenandClaude Opus 5.5 c7ce924e5a fix: library IDs stay hidden without library access (ruling P13)
Outline, node-get, write outlines, the render summary and replace-text's
opaque-node match name no library ID unless the library group is visible
and the user has divi_library; read-only still names them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 15:00:39 +02:00
janniclas.loosenandClaude Opus 5.5 a413f761e7 refactor: DiviSaver docblocks, one diviWritable field, REASON_CREATE with the constants (M-4, M-5, M-13)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 04:22:04 +02:00
janniclas.loosenandClaude Opus 5.5 1b42f9b640 fix: lit/divi-node-copy from a library entry needs the insert rights (I-1, L5)
A library entry as source now requires LibraryAccess::canInsert() (add_library,
writable library group) and follows lit-library-insert's Tools-tab state
(disabled -> unsupported). DiviPageLoader::library() gets its caller.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 04:06:56 +02:00
janniclas.loosenandClaude Opus 5.5 2729e2800e docs: guides, readme and spec for the Divi Library (v0.4.0)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 03:33:38 +02:00
janniclas.loosenandClaude Opus 5.5 6f6c691b5d feat: lit/divi-node-copy between pages and library entries
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 03:12:57 +02:00
janniclas.loosenandClaude Opus 5.5 7fe91c2bdb feat: lit-library-insert as copy or global instance in the builder's format (E5)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 02:27:16 +02:00
janniclas.loosenandClaude Opus 5.5 b7c714939d feat: group Divi-Bibliothek with lit/library-list
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 01:29:37 +02:00
janniclas.loosenandClaude Opus 5.5 d66ad36c2e feat: Divi tools write library entries; global ones with dry run, confirm and backup (E2, F2)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 01:15:58 +02:00
janniclas.loosenandClaude Opus 5.5 48ecc627aa feat: Divi read tools accept library entries (library access, E1/E3)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 01:02:25 +02:00
janniclas.loosenandClaude Opus 5.5 b24eb6c3e9 fix(security): no direct HTTP access to plugin PHP files (audit L2, cheap part)
Every file under src/ exits outside WordPress (defined('ABSPATH') ||
exit; after the use block, so a direct request no longer prints a fatal
error with the server path); divi-convert-fixture.php gets the WP_CLI
guard the other integration scripts have. A unit test keeps both true;
PSR1 side-effects warning excluded for the guard.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 19:32:12 +02:00
janniclas.loosenandClaude Opus 5.5 4d4bf57c9f fix(security): refuse OAuth authorize/consent for users without access (audit L1)
mcp-oauth has no filter for this, so AuthorizeGate runs on
template_redirect before its router and stops the browser endpoints
(authorize, authorize-callback, consent) for logged-in users without
lit_mcp_use with "Dein Benutzer hat keinen Zugriff auf LIT MCP." (403).
Login redirect, token and revoke stay mcp-oauth's.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 19:30:54 +02:00
janniclas.loosenandClaude Opus 5.5 5f596b8a17 fix(security): content-create divi follows the Divi group switches (audit M2)
The divi input of lit/content-create is refused with unsupported when
lit/divi-insert is disabled or the Divi group is disabled or read-only
(ExposurePolicy::allows as a cross-group gate, asked at execute time).
content-create without divi keeps working. Adds a registrar test that
read-only write tools are never registered, so execute-ability can't
reach them either.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 19:16:35 +02:00
janniclas.loosenandClaude Opus 5.5 0f23192873 feat: Protokoll tab as a core-style list table
The change summary is the wide primary column (key "title", so it cannot
be hidden) with the tool's human label below and row actions "Revision
ansehen" / "Objekt öffnen". Objects get human names ("Seite: Kontakt",
"Menü: …", "Einstellungen: Titel der Website"; deleted/trashed marked),
primed per page with one query each for posts, menus and users. Times are
relative within 24 h. Non-ok results show a badge and a marked row instead
of an Ergebnis column. Page size and columns via Screen Options; the tool
filter shows labels grouped by integration, dates have visible labels,
and an active filter offers "Filter zurücksetzen" (also in the empty state).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 19:02:47 +02:00
janniclas.loosenandClaude Opus 5.5 10c98cd3c6 docs: Divi guides shortform/placeholders, hints name the write tools; test: Divi write end-to-end; version 0.3.0
- Hints (PostPresenter::DIVI_NOTE, outline, catalog) and server instructions (tree_rev rule)
  name the Divi write tools; guides divi-shortform and divi-placeholders, additions to
  divi-structure, divi-attrs, overview (tool groups, 'nur lesen'), workflows, content-types.
- D7 wording and the S7 exception in readme, guides and spec 1.3/5.2; readme 0.3.0.
- ToolNamingTest: every referenced guide topic exists; overview lists exactly the topics.
- tests/Integration/divi-write-smoke.sh: all write tools via OAuth, editor without
  unfiltered_html with benign probes (S6), Divi's own save filters on the new fixture
  synthetic-divi-filters.html (S7); admin-render.php accepts the new wrap class.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 17:13:59 +02:00
janniclas.loosenandClaude Opus 5.5 843f45aeec feat: admin settings page UI/UX pass with WordPress-native patterns
- Header: h1 + logo in a wrapping flex row, hr.wp-header-end before the tabs,
  aria-current on the active tab; own CSS/JS enqueued only on this screen.
- Verbindung: ordered "So verbindest du Claude" steps, copy button (core
  clipboard.js + wp.a11y.speak), Site-Health-style status list, German details.
- Zugriff: roles as form-table fieldset, connections with site date format,
  empty-state row, confirm on revoke; ConnectionUsage records last use via
  WP_Application_Passwords::record_application_password_usage (once a day).
- Tools: plain-language legend, counter as inline notice, groups as core
  postboxes (postbox.js toggles, per-user closed state, summary when closed),
  fixed column widths with new "Art" column, submit above and below.
- Protokoll: site-timezone times with UTC tooltip, result icons, filters with
  labels in the list table nav, retention link to Limits.
- Limits: short labels with units and descriptions; snapshot count hidden but
  preserved.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 16:50:58 +02:00
janniclas.loosenandClaude Opus 5.5 5965e32acb feat: lit/content-create with Divi short form
New input divi (1-30 sections, short form like lit-divi-insert) builds a Divi 5
layout in one divi/placeholder. The whole description is checked before the
insert (Divi's map for "no entry yet"); the draft is inserted with its normal
WordPress fields only, then DiviContentComposer composes again bound to the new
entry and stores it via DiviSaver::saveNew (same kses window as save(), strict
DiviFlags). A refusal or failure deletes the draft. Result adds tree_rev and the
outline.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 16:46:50 +02:00
janniclas.loosenandClaude Opus 5.5 3efcfaabec merge: tool groups with inherited mode and 'nur lesen' per group
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 16:32:39 +02:00
janniclas.loosenandClaude Opus 5.5 bb85868192 fix: answer /.well-known OAuth discovery without a canonical redirect; smoke checks the real path
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 16:27:25 +02:00
janniclas.loosenandClaude Opus 5.5 776dbf8f4a feat: group tools by integration with inherited group mode and "nur lesen" switch
Tools tab shows one block per integration with a group mode (inherited by its
tools) and a read-only switch that disables all non-readonly abilities of the
group. ExposurePolicy resolves tool override > group override > tool default;
lit/guide keeps its default, direct-only tools fall back to direct under a
group "indirekt". Group entries live in lit_mcp_exposure under "@group:<id>"
and "@readonly:<id>"; the old flat format stays valid. The ability->group map
comes lazily from IntegrationRegistry (Divi is not loaded at plugins_loaded).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 16:17:05 +02:00
janniclas.loosenandClaude Opus 5.5 68ca4f45ec feat: Loosen-IT logo top right on the settings page
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 15:26:44 +02:00
janniclas.loosenandClaude Opus 5.5 110beb7698 feat: lit/divi-insert and lit/divi-update
All-or-nothing at ability level (S39), duplicate ids refused (S14),
set and attrs on the same path refused (S38), invalid_attr_path error.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 15:15:37 +02:00
janniclas.loosenandClaude Opus 5.5 2f4dcf9ce4 feat: Divi module catalog, attribute paths, short form and lit/divi-catalog
Adds per-path attribute kind (text/richtext/code/url/image/color/enum/
onoff/number/list/icon), derived from Divi's field component metadata
where an attribute path names one unambiguously (module.paths() itself
is unchanged; kinds() is a new, separate lookup exposed as path_kinds
on lit/divi-catalog's module detail). This is not in the task-4 brief;
it is added because 2b's sanitization routing (ruling R3) needs a
metadata-derived field kind per attribute path. Verified live against
the full 100-module catalog (564/4358 paths resolve a kind; the rest
default to "unknown" and fall back to 2b's key-name routing).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 11:48:27 +02:00
janniclas.loosenandClaude Opus 5.5 7f58301a71 docs: readme with site-wide effects, media guide; test: media/admin end-to-end; version 0.2.0
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 04:51:11 +02:00
janniclas.loosenandClaude Opus 5.5 522f5bbd19 feat: change log tab with filters, revision links and clear button
ChangeLog gains query()/abilities()/clear() (filters: ability, user,
result, date range - all optional and additive). LogTab/LogListTable
render the "Protokoll" admin tab: WP_List_Table with pagination, links
to the post/attachment/nav_menu edit screen by object_type, a revision
link shown only when the user may edit the revision's parent post, and
a nonce+manage_options-gated "Protokoll leeren" with a JS confirmation
and highlighted 'partial' rows.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 04:12:13 +02:00
janniclas.loosenandClaude Opus 5.5 bca35f6166 feat: tools and limits settings tabs
Adds Einstellungen → LIT MCP → Tools (direct/indirect/disabled per
ability, only ExposurePolicy-allowed modes offered) and → Limits
(upload size, log retention, snapshot count), wired into Plugin.php.

Ruling Q11b (carried from task 6): overview.md notes that direct
visibility is configurable; hints in src/ that name a tool which is
direct by default but can be switched to indirect (content-get,
content-query, content-types, post-publish, media-search) now use the
neutral "lit/<name> (direkt: lit-<name>)" form so they stay correct
after an admin override. lit/guide (always direct) and the
media-preview/-download DIRECT_ONLY tools are unaffected.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 03:47:40 +02:00
janniclas.loosenandClaude Opus 5.5 eee1840411 feat: access tab with allowed roles and connection revocation
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 03:33:54 +02:00
janniclas.loosenandClaude Opus 5.5 f084c47311 feat: settings page with connection tab, admin notices and site health test
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 03:21:56 +02:00
janniclas.loosenandClaude Opus 5.5 2674bf2ed1 feat: hide tool list and instructions from users without LIT MCP access
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 03:13:05 +02:00
janniclas.loosenandClaude Opus 5.5 2f8a9f0c61 feat: configurable exposure policy for direct, indirect and disabled tools
Introduces ExposurePolicy (option lit_mcp_exposure) deciding per ability
whether it is a direct MCP tool, only reachable via mcp-adapter's
execute-ability meta-tool, or disabled entirely (not registered with the
Abilities API at all). Ability::isDirect() remains the default when no
override applies. lit/guide can never be disabled or made indirect;
lit/media-preview and lit/media-download (image/embedded-resource results)
can never be made indirect, only direct or disabled.

AbilityRegistrar and ServerRegistrar take an optional ExposurePolicy and
use it to filter registered abilities / compute the direct tool list.
IntegrationRegistry::directAbilityNames() is removed (superseded by
ExposurePolicy::directNames()). InstructionsBuilder now also takes the
policy and lists the currently direct tools by name (lit-<name>), noting
the rest are reachable via mcp-adapter-execute-ability as lit/<name>.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 03:04:14 +02:00
janniclas.loosenandClaude Opus 5.5 a2a2da1ae7 feat: media usage finder and media-get tool
Usage search distinguishes certain (ID referenced) and possible (file URL
only) usages, hides titles the user cannot read, and keeps queries bounded.
MediaGuard checks per-attachment capabilities and refuses trashed media
unless the caller opts in.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-26 01:54:55 +02:00
janniclas.loosenandClaude Opus 5.5 98a910f056 feat: content-types tool and WordPress integration
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-25 22:21:29 +02:00
janniclas.loosenandClaude Opus 5.5 261972751f feat: change log table with retention cron and limits option
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-25 21:58:15 +02:00
janniclas.loosenandClaude Opus 5.5 0e3332ad3e fix: close etappe-0 whole-branch review findings
- Autoloader: add automattic/jetpack-autoloader and load
  vendor/autoload_packages.php; require wordpress/mcp-adapter directly (^0.5).
- ServerRegistrar: make the adapter create_server() call and the
  OAuthServerRegistrar class_exists() check injectable so createServer()'s
  unhook-before-create ordering and the "mcp-oauth absent" branch are unit
  tested; add a smoke-test check that booting REST triggers no
  _doing_it_wrong().
- mcp-smoke.sh: assert mcp-adapter's default server route 404s, and that the
  subscriber role-gate denial actually carries our/the adapter's denial text
  (not just any isError/error).
- Guard tests/Integration/mint-token.php and tec-probe.php with
  `defined('WP_CLI') && WP_CLI || exit;`; add .gitattributes export-ignore
  for tests/docs-superpowers/.superpowers/phpunit/phpcs config.
- Security: add Server/RequestContext, tracking via
  rest_request_before_callbacks whether the current REST dispatch is our
  OAuth-protected /mcp/mcp-oauth-server route; AbilityRegistrar's
  permission_callback now denies (after the role gate) when abilities are
  invoked outside that route. Wired in Plugin::boot().
- Minors: single Plugin::VERSION constant used by ServerRegistrar;
  IntegrationRegistry caches its computed abilities list; tec-probe.php
  checks wp_insert_post's result and cleans up its probe post in a
  try/finally.

composer test: 47/47 green. composer lint: clean. Full mcp-smoke.sh run ends
ALL CHECKS PASSED (plus the expected /.well-known WARN).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-25 19:23:09 +02:00