Fix raw hooks: plugin-side hookRawMethod with Advice instrumentation

Remove the planted isContactsTabVisible() hook target and app-side visibility
conditionals (that was cheating). Plugins now declare raw JVM targets directly
via hookRawMethod on existing methods like MainScreenKt.selectMainPage,
ContactsTabKt.ContactsTab, NavigationBarKt.NavigationBarItem, and Logger.d.

Replace ByteBuddy MethodDelegation (schema-changing) with Advice-based
ClassReloadingStrategy so hooks actually install at runtime. Fix Logger hook
signature for Kotlin object instance methods. Add chat banner z-index fix and
PluginEngine.hostRevision to recompose MainScreen after plugin load.

Co-authored-by: denis0001-dev <denis0001.dev@ya.ru>
This commit is contained in:
Cursor Agent
2026-09-17 00:17:25 +00:00
Unverified
parent ab4f6fcc53
commit 1ff4503be9
21 changed files with 536 additions and 89 deletions
@@ -8,6 +8,7 @@ interface PluginHostBridge {
fun registerSendMessageHook(pluginId: String, priority: Int, handler: (SendMessageHookContext) -> HookResult<SendMessageHookContext>)
fun registerFeatureOverride(pluginId: String, featureId: String, provider: () -> Boolean?)
fun registerMenuItem(pluginId: String, item: MenuItemData)
fun registerUiOverlay(pluginId: String, slot: String, title: String, message: String)
fun showBulletin(message: String)
fun hookSharedMethod(
pluginId: String,
@@ -16,6 +17,16 @@ interface PluginHostBridge {
before: ((Array<Any?>) -> HookResult<Array<Any?>>)?,
after: ((Array<Any?>, Any?) -> HookResult<Any?>)?,
): () -> Unit
fun hookRawMethod(
pluginId: String,
className: String,
methodName: String,
paramTypeNames: Array<String>,
priority: Int,
before: ((Array<Any?>) -> HookResult<Array<Any?>>)?,
after: ((Array<Any?>, Any?) -> HookResult<Any?>)?,
): () -> Unit
}
abstract class BasePlugin {
@@ -31,6 +42,7 @@ abstract class BasePlugin {
open fun onPluginLoad() {}
open fun onPluginUnload() {}
open fun onAppEvent(event: AppEvent) {}
open fun onMenuItemClick(key: String) {}
open fun createSettings(): List<PluginSetting> = emptyList()
protected fun log(message: String) = bridge.log(pluginId, message)
@@ -63,6 +75,10 @@ abstract class BasePlugin {
bridge.registerMenuItem(pluginId, item)
}
protected fun registerUiOverlay(slot: String, title: String, message: String) {
bridge.registerUiOverlay(pluginId, slot, title, message)
}
protected fun showBulletin(message: String) {
bridge.showBulletin(message)
}
@@ -73,6 +89,23 @@ abstract class BasePlugin {
before: ((Array<Any?>) -> HookResult<Array<Any?>>)? = null,
after: ((Array<Any?>, Any?) -> HookResult<Any?>)? = null,
): () -> Unit = bridge.hookSharedMethod(pluginId, hookId, priority, before, after)
protected fun hookRawMethod(
className: String,
methodName: String,
paramTypeNames: Array<String> = emptyArray(),
priority: Int = 0,
before: ((Array<Any?>) -> HookResult<Array<Any?>>)? = null,
after: ((Array<Any?>, Any?) -> HookResult<Any?>)? = null,
): () -> Unit = bridge.hookRawMethod(
pluginId,
className,
methodName,
paramTypeNames,
priority,
before,
after,
)
}
object PluginSettingsReload {