aboutsummaryrefslogtreecommitdiffhomepage
path: root/docs/dev/plugin-stub-generation.md
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-05 03:58:03 +0900
committernsfisis <nsfisis@gmail.com>2026-08-05 03:58:03 +0900
commit9b444a9a879b75a6af3d3c7ba8b9a4294574c3ec (patch)
treeb1041b55bc3ed36a391370cc2f5ececc8cb386b2 /docs/dev/plugin-stub-generation.md
parentbe3458128ef09b3d1074b134f2822162e077e165 (diff)
downloadphp-shirabe-9b444a9a879b75a6af3d3c7ba8b9a4294574c3ec.tar.gz
php-shirabe-9b444a9a879b75a6af3d3c7ba8b9a4294574c3ec.tar.zst
php-shirabe-9b444a9a879b75a6af3d3c7ba8b9a4294574c3ec.zip
feat(plugin): run plugin-provided commands in a worker-side application
A same-FQCN Composer\Console\Application, hand-written under the new php/runtime/ tree, hosts CommandProvider commands inside the PHP worker: PhpCommandProxy overrides run() and forwards the stringified input, so the real Symfony machinery binds, validates and executes against the live command object, while help/list render Rust-side from a definition read back at construction. Reverse \Shirabe\RustCommandStub rows let a plugin command invoke built-in commands back in the Rust process, keeping every command on the side whose helper set it was written for. Composer\EventDispatcher\Event moves from a generated stub to a dual-mode runtime class: the real BaseCommand::initialize constructs a PreCommandRunEvent natively in the worker, which a proxy-only constructor guard rejected. Its PRE_COMMAND_RUN dispatch reaches a new EventDispatcher stub whose dispatch supports the observably-no-op no-listener case and fails explicitly otherwise. The stub generator now accepts runtime-provided classes as stub bases (never as targets) and cross-checks the Application handoff property table against the real class. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'docs/dev/plugin-stub-generation.md')
-rw-r--r--docs/dev/plugin-stub-generation.md19
1 files changed, 16 insertions, 3 deletions
diff --git a/docs/dev/plugin-stub-generation.md b/docs/dev/plugin-stub-generation.md
index 09bb5625..e10c0e9c 100644
--- a/docs/dev/plugin-stub-generation.md
+++ b/docs/dev/plugin-stub-generation.md
@@ -25,6 +25,12 @@ Inputs:
* `targets.list` — the FQCNs to emit, stub base classes before their subclasses.
Growing the stub set means adding a line here and regenerating.
+* the hand-written classes under `crates/shirabe-php-rpc/php/runtime/` (their
+ FQCNs derive from the file paths). These are two-world implementations with
+ behavior of their own — not mechanical proxies — so the generator never emits
+ them, but it accepts them as base classes of generated stubs (computing the
+ inherited surface from the real Composer class the runtime file mirrors) and
+ fails if a `targets.list` entry would shadow one.
* the Composer checkout (`composer/`, override with `--composer-root=`); the
generator locates sources through the checkout's own PSR-4 autoload map, so
interfaces from vendor packages (e.g. `Psr\Log\LoggerInterface`) resolve too.
@@ -83,12 +89,19 @@ Generation fails — instead of emitting something quietly wrong — on:
other than `__toString`/`__clone`,
* an omitted override diverging from the inherited stub signature,
* a subclass target listed before its base class, or extending a class that is
- not a target,
+ neither a target nor provided by `php/runtime/`,
+* a target whose FQCN is also provided by `php/runtime/`,
* non-public class constants (materializing them is unsupported so far).
`generate-stubs` (in both modes) additionally fails when a `.php` file exists
-under the stubs directory that no target produces, or when `STUB_FILES` in
-`crates/shirabe-php-rpc/src/lib.rs` does not embed every generated file.
+under the stubs directory that no target produces, or when `STUB_FILES` /
+`RUNTIME_FILES` in `crates/shirabe-php-rpc/src/lib.rs` does not embed every
+generated stub / runtime file. It also cross-checks the handoff property table
+for `Composer\Console\Application` (declared in `generate-stubs` itself) against
+the real class: a property upstream adds without a handoff classification — or a
+table row the class no longer declares — fails generation, so the worker-side
+runtime application can never silently drop plugin-visible state after a
+Composer version bump.
When a future Composer release adds a public member the emitter cannot handle,
these assertions surface it at generation time; extending the emitter (or