appctl_plugin_sdk/lib.rs
1//! `appctl-plugin-sdk`
2//!
3//! Stable schema types and the dynamic-plugin ABI for the `appctl` CLI agent.
4//!
5//! Consumers fall into two groups:
6//!
7//! * **Built-in sync plugins** inside the main `appctl` crate — they implement
8//! the async [`SyncPlugin`] trait directly.
9//! * **Out-of-process dynamic plugins** shipped as `cdylib`s living under
10//! `~/.appctl/plugins/` — they expose a single `#[no_mangle] extern "C"`
11//! entry point returning a [`PluginManifest`] plus a JSON-in / JSON-out
12//! `introspect` function. See [`declare_plugin!`].
13
14pub mod ffi;
15pub mod schema;
16
17pub use ffi::{PluginManifest, PluginVtable, SDK_ABI_VERSION};
18pub use schema::*;
19
20use anyhow::Result;
21use async_trait::async_trait;
22
23/// Runtime inputs passed to a sync plugin.
24#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
25pub struct SyncInput {
26 #[serde(default)]
27 pub source: Option<String>,
28 #[serde(default)]
29 pub base_url: Option<String>,
30 #[serde(default)]
31 pub options: serde_json::Map<String, serde_json::Value>,
32}
33
34/// A sync plugin introspects an application and returns a [`Schema`].
35///
36/// Built-in plugins in the main `appctl` crate implement this trait directly.
37/// Dynamic plugins use the C ABI in [`ffi`] and are adapted by the loader.
38#[async_trait]
39pub trait SyncPlugin: Send + Sync {
40 /// Stable identifier, e.g. `"openapi"`, `"rails"`, `"airtable"`.
41 fn name(&self) -> &str;
42
43 /// Introspect the target and build a schema.
44 async fn introspect(&self) -> Result<Schema>;
45}
46
47/// Convenience re-export for plugin authors.
48pub mod prelude {
49 pub use super::ffi::{PluginManifest, PluginVtable, SDK_ABI_VERSION};
50 pub use super::schema::*;
51 pub use super::{SyncInput, SyncPlugin};
52 pub use crate::declare_plugin;
53 pub use anyhow::{Result, anyhow, bail};
54 pub use async_trait::async_trait;
55}