feat(plugins): plugin pages, per-user config, capabilities gate, mobile/telegram refactors

- Plugin HTTP routes + web pages (plugin-page-host, plugin-catalog, plugin-detail)
- Plugin access grants + per-user config (DB tables + API + frontend forms)
- Capabilities-based guard (caps.rs) replacing role-id checks
- Mobile connector: message routing, payload types, router refactor
- Telegram bot: auth flow, event handling improvements
- Honcho plugin: substantial rework
- Sidebar: plugin pages integration, role-driven visibility
- i18n: new strings for plugins, connectors, capabilities
- Remove unused mascot asset
This commit is contained in:
2026-07-19 20:47:09 +01:00
parent f85876350e
commit ba911ae8cb
50 changed files with 3186 additions and 305 deletions
+28 -1
View File
@@ -48,7 +48,7 @@ use tokio::task::JoinHandle;
use tokio_util::sync::CancellationToken;
use tracing::{info, warn};
use core_api::plugin::{Plugin, PluginContext};
use core_api::plugin::{Plugin, PluginContext, PluginPage};
use skald_relay_client::{ClientState as RelayClientState, RelayClient, RelayClientConfig, SeedSource};
pub use agent::{ClientInfo, ClientState, PairingHandle, RelayAgent};
@@ -232,6 +232,10 @@ impl Plugin for MobileConnectorPlugin {
}
fn is_running(&self) -> bool { self.running.load(Ordering::Relaxed) }
/// Access is the device→user binding (§13), not a `plugin_access` grant, so
/// the admin Plugins UI hides the "User access" checklist for this plugin.
fn manages_own_access(&self) -> bool { true }
fn config_schema(&self) -> Value {
json!({
"type": "object",
@@ -305,6 +309,29 @@ impl Plugin for MobileConnectorPlugin {
Some(router::build(Arc::clone(&self.inner)))
}
/// Two admin-only console pages served from this plugin's own router
/// (`web/*.js`). `manages_own_access` already hides them from non-admins.
fn web_pages(&self) -> Vec<PluginPage> {
vec![
PluginPage {
page_id: "pairing",
title: "Pair a device".into(),
icon: "qr-code",
entry: "web/pairing.js".into(),
admin_only: true,
priority: 10,
},
PluginPage {
page_id: "devices",
title: "Mobile devices".into(),
icon: "phone",
entry: "web/devices.js".into(),
admin_only: true,
priority: 20,
},
]
}
/// Control tools (plugin.md §11). They close over the plugin itself as a
/// `RelayAgent` and call into it lazily, so building them before the runloop
/// starts is fine — they fail gracefully while it is stopped.