zerolaunch_plugin_sdk_rust/lib.rs
1//! ZeroLaunch Rust plugin SDK.
2//!
3//! Provides a `run()` function that wraps a user's `Plugin` trait implementation
4//! in a JSON-RPC 2.0 stdio loop, handling the LSP-style frame protocol and
5//! dispatching incoming requests.
6//!
7//! # Usage
8//!
9//! ```ignore
10//! fn main() {
11//! zerolaunch_plugin_sdk_rust::run(MyPlugin::new())
12//! }
13//! ```
14
15pub mod host_proxy;
16pub mod logging;
17pub mod runtime;
18
19pub mod trace;
20
21use std::sync::OnceLock;
22
23pub use host_proxy::HostProxy;
24pub use runtime::{host, run, PluginApp};
25pub use trace::{instrument, span_for, with_trace};
26
27/// 当前插件 id:`plugin/initialize` 握手时由宿主下发并写入,
28/// 供 `t_key()` 自动补命名空间前缀。
29static PLUGIN_ID: OnceLock<String> = OnceLock::new();
30
31/// 记录宿主下发的插件 id(SDK 运行时握手时调用,仅一次)。
32pub(crate) fn set_plugin_id(plugin_id: &str) {
33 let _ = PLUGIN_ID.set(plugin_id.to_string());
34}
35
36/// 生成带当前插件命名空间前缀的翻译键(`plugin.<当前插件id>.<key>`)。
37///
38/// 插件 id 由 SDK 在 `plugin/initialize` 握手时自动注入,无需手动传入;
39/// 配合插件目录 `i18n/<lang>.json` 语言包使用:宿主加载插件时读取该目录、
40/// 统一加前缀合并进翻译目录,前端对 key-or-literal 文本(schema 标签、
41/// 结果项动作 label 等)自动翻译;未提供语言包时原样显示 key 派生文本。
42///
43/// # Panics
44///
45/// 在插件运行时初始化(`run()` 之后的握手)之前调用将 panic,
46/// 因为此时尚不知道插件 id。
47/// 从环境变量 `ZEROLAUNCH_PLUGIN_ID` 预置插件 id,使 `t_key()` 可在组件构造
48/// (`main()` 中、`run()` 之前)使用。宿主 spawn 插件时注入该变量;
49/// 非宿主环境(本地调试等)可不调用,此时 `t_key()` 在握手前调用仍 panic。
50pub fn init() {
51 if let Ok(id) = std::env::var("ZEROLAUNCH_PLUGIN_ID") {
52 set_plugin_id(&id);
53 }
54}
55
56pub fn t_key(key: &str) -> String {
57 let plugin_id = PLUGIN_ID
58 .get()
59 .expect("t_key 必须在插件运行时初始化后调用(run() 之后)");
60 format!("plugin.{plugin_id}.{key}")
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 /// t_key 自动补当前插件 id 前缀(id 在 plugin/initialize 握手时注入)。
68 #[test]
69 fn t_key_prefixes_current_plugin_id() {
70 set_plugin_id("com.example.hello-world");
71 assert_eq!(t_key("greeting"), "plugin.com.example.hello-world.greeting");
72 assert_eq!(t_key("sayHello"), "plugin.com.example.hello-world.sayHello");
73 }
74}