Skip to content

Wire TS-callable codegen dispatch for perry/plugin (21 runtime FFI functions currently unreachable from user code) #189

Description

@proggeramlug

Context

Surfaced during the v0.5.299 docs audit. The entire perry/plugin module — five docs pages worth of API surface — is fully implemented in the runtime but unreachable from TypeScript code.

Runtime FFI in crates/perry-runtime/src/plugin.rs (21 exported functions):

  • perry_plugin_load, perry_plugin_unload
  • perry_plugin_register_hook, perry_plugin_emit_hook
  • perry_plugin_invoke_tool
  • perry_plugin_list_plugins
  • (plus the rest — see the #[no_mangle] pub extern "C" fn perry_plugin_* block in that file)

But crates/perry-codegen/src/lower_call.rs has no module == "perry/plugin" branch in lower_call.rs or lower_native_method_call. Receiver-less native calls (loadPlugin(name)) fall through to the no-op stub at lower_call.rs:2849-2854. Instance-method calls (api.registerHook(...)) similarly have no PluginApi entry in the receiver-method dispatcher.

Verified end-to-end: a host-side test program calling loadPlugin(...) compiles + links + runs but every plugin call is silently elided.

What to do

Two pieces, mirroring the existing perry/ui and perry/system wiring:

  1. Static-function dispatch — add module-level entries in lower_call.rs mapping ("perry/plugin", "loadPlugin") → "perry_plugin_load", etc., for every receiver-less call.

  2. Instance-method dispatchPluginApi's methods (registerHook, invokeTool, emit, …) need a method-table entry in the same shape as the existing Window instance-method dispatch (search lower_call.rs for method: "show", runtime: "perry_ui_window_show" for the pattern).

The runtime's argument shapes are documented per-function in crates/perry-runtime/src/plugin.rs. Most are (string_ptr, payload_ptr) style — match the existing perry/ui dispatcher's arg-coercion logic.

Acceptance criteria

  • Every perry/plugin function listed in crates/perry-runtime/src/plugin.rs is reachable from TypeScript.
  • All ,no-test fences in docs/src/plugins/{overview,creating-plugins,hooks-and-events,native-extensions,appstore-review}.md (~25 total) can be converted to verified {{#include}} extracts using the anchor pattern (see e.g. docs/examples/ui/styling/snippets.ts).
  • Each plugin docs page drops its "Status: not yet wired into any codegen path" callout.
  • At least one runnable doc-tests example end-to-end loads a stub plugin, registers a hook, emits the hook, and prints the result. Byte-diffed against an _expected/ stdout.

Pointers

  • Runtime impl: crates/perry-runtime/src/plugin.rs
  • Codegen dispatcher: crates/perry-codegen/src/lower_call.rs
    • Static-function pattern: search for UiSig { method: "isDarkMode"
    • Instance-method pattern: search for method: "show", runtime: "perry_ui_window_show"
  • Receiver-less early-out (the bug): lower_call.rs:2849-2854
  • Type defs (may need extending): consider adding types/perry/plugin/index.d.ts if it doesn't already exist.

Estimated size

Substantial — ~150-300 lines of compiler code plus the matching type declarations and at least one runnable plugin example. Multi-day work historically.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew capability or improvement

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions