Declare the experimental plugin search API (#36402)

## What changed

- Add the experimental `plugin/search` request with search term, scope, working-directory, cursor, and limit parameters.
- Define paginated results that include each plugin's marketplace name and optional local marketplace path.
- Route the request through app server while returning method-not-found until the search implementation is available.

## Testing

- Add an app-server test that verifies `plugin/search` returns JSON-RPC error `-32601` with the expected not-implemented message.

GitOrigin-RevId: 755400468331f0887f7da7d933195c347aadf6d0
This commit is contained in:
Greg Brisebois
2026-07-31 23:08:55 +00:00
committed by copyberry
parent 003ec63bba
commit 64b2a3008e
18 changed files with 213 additions and 0 deletions
@@ -729,6 +729,12 @@ client_request_definitions! {
serialization: None,
response: v2::PluginListResponse,
},
#[experimental("plugin/search")]
PluginSearch => "plugin/search" {
params: v2::PluginSearchParams,
serialization: None,
response: v2::PluginSearchResponse,
},
PluginInstalled => "plugin/installed" {
params: v2::PluginInstalledParams,
serialization: None,
@@ -18,6 +18,7 @@ mod model;
mod notification;
mod permissions;
mod plugin;
mod plugin_search;
mod process;
mod realtime;
mod remote_control;
@@ -45,6 +46,7 @@ pub use model::*;
pub use notification::*;
pub use permissions::*;
pub use plugin::*;
pub use plugin_search::*;
pub use process::*;
pub use realtime::*;
pub use remote_control::*;
@@ -0,0 +1,47 @@
use super::PluginSummary;
use crate::JsonSchema;
use crate::TS;
use codex_utils_absolute_path::AbsolutePathBuf;
use serde::Deserialize;
use serde::Serialize;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct PluginSearchParams {
pub search_term: String,
#[ts(optional = nullable)]
pub scope: Option<PluginSearchScope>,
#[ts(optional = nullable)]
pub cwds: Option<Vec<AbsolutePathBuf>>,
#[ts(optional = nullable)]
pub cursor: Option<String>,
#[ts(optional = nullable)]
pub limit: Option<u32>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase", export_to = "v2/")]
pub enum PluginSearchScope {
Global,
Workspace,
Personal,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct PluginSearchResult {
pub plugin: PluginSummary,
pub marketplace_name: String,
pub marketplace_path: Option<AbsolutePathBuf>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct PluginSearchResponse {
pub data: Vec<PluginSearchResult>,
pub next_cursor: Option<String>,
}