aboutsummaryrefslogtreecommitdiffhomepage
path: root/docs/dev/php-rpc.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/php-rpc.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/php-rpc.md')
-rw-r--r--docs/dev/php-rpc.md49
1 files changed, 39 insertions, 10 deletions
diff --git a/docs/dev/php-rpc.md b/docs/dev/php-rpc.md
index a1093ec5..298b4059 100644
--- a/docs/dev/php-rpc.md
+++ b/docs/dev/php-rpc.md
@@ -128,18 +128,47 @@ function; an unknown name is an explicit error. Notable internal helpers:
even autoloadable there, i.e. no Composer PHP runtime and therefore no observer code.
- `__shirabe_get_property` — for testing only: reads a public property of a P-table entity.
- `__shirabe_oracle_roundtrip` — codec oracle support for tests.
+- `__shirabe_console_application_boot` — builds the worker-side `Composer\Console\Application`
+ (the `php/runtime/` definition) from the Rust handoff: the shared `$composer`/`$io` proxies,
+ the initial working directory and disable-by-default flags, `\Shirabe\RustCommandStub` rows
+ mirroring the built-in commands, and the live plugin-provided command entities.
+- `__shirabe_run_console_application` — runs one stringified command line through a booted
+ worker-side application; output goes to the inherited stdio, the exit code returns over the
+ wire, and a failure propagates as a Throw (the booted application does not catch exceptions).
+- `__shirabe_read_command_definition` — reads a command's input definition (plus help text and
+ extra usages) as plain data, so the Rust side mirrors it for `help`/`list` rendering.
-## Proxy stubs
+The runtime service endpoint (handle 0) answers `__shirabe_find_file` (autoload lookups) and
+`__shirabe_run_rust_command` — the reverse half of the two-world command split: a
+`\Shirabe\RustCommandStub` forwards its stringified input here and the built-in command runs in
+the Rust process, against the Rust-side application state.
-`php/stubs/` holds the proxy stub classes (`Composer\EventDispatcher\Event`,
-`Composer\Script\Event`, `Composer\PartialComposer`, `Composer\Composer`, and the
-`Composer\IO\{BaseIO,ConsoleIO,BufferIO,NullIO}` hierarchy). They are generated by
-`scripts/plugin-stub-generator/generate-stubs` and must not be edited by hand; see
-`docs/dev/plugin-stub-generation.md`. They are autoloaded with highest priority so a proxied FQCN can
-never be shadowed by the real implementation; `__shirabe_require` restores that priority after
-loading code that prepends its own autoloader. Stubs are interned per rhandle
-(`WeakReference`-based registry) so identity (`===`) holds, and their destructors send
-`ReleaseRustHandle`.
+## Proxy stubs and runtime classes
+
+`php/stubs/` holds the proxy stub classes (`Composer\Script\Event`, `Composer\PartialComposer`,
+`Composer\Composer`, the `Composer\IO\{BaseIO,ConsoleIO,BufferIO,NullIO}` hierarchy, the
+package/repository graph, and `Composer\EventDispatcher\EventDispatcher`). They are generated
+by `scripts/plugin-stub-generator/generate-stubs` and must not be edited by hand; see
+`docs/dev/plugin-stub-generation.md`.
+
+`php/runtime/` holds hand-written worker-side classes that are not mechanical proxies:
+
+- `Composer\Console\Application` — a same-FQCN two-world implementation (never the real class
+ file): plugin-provided commands run under it inside the worker, and its Composer-specific
+ surface (`getIO()`/`getComposer()`/...) answers from the Rust handoff.
+- `Shirabe\RustCommandStub` — the reverse stub for built-in commands registered into that
+ application.
+- `Composer\EventDispatcher\Event` — dual-mode: revived from a Rust handle it proxies like a
+ generated stub, while a natively-constructed instance (real Composer code in the worker does
+ `new PreCommandRunEvent(...)`, whose parent constructor lands here) is a faithful in-process
+ port of the real base class and crosses the wire as a P-table entity
+ (`__shirabeRustHandleDescriptor()` returns null in native mode).
+
+Both sets are written into the same autoload directory at worker spawn and resolved with
+highest priority, so these FQCNs can never be shadowed by the real implementation;
+`__shirabe_require` restores that priority after loading code that prepends its own autoloader.
+Stubs are interned per rhandle (`WeakReference`-based registry) so identity (`===`) holds, and
+their destructors send `ReleaseRustHandle`.
## The P table