1use std::sync::Arc;
5
6use serde_json::{Map, Value};
7
8use crate::ctx::Ctx;
9use crate::errors;
10use crate::spec::JsonMap;
11use crate::spec::command::{CliHints, HTTPHints, MCPHints};
12use crate::spec::field::FieldMeta;
13use crate::spec::schema::Schema;
14
15pub struct Entry {
16 pub name: String,
17 pub summary: String,
18 pub description: String,
19
20 pub input_schema: Schema,
22
23 pub output_schema: Option<Schema>,
26
27 pub root: FieldMeta,
30
31 pub cli: CliHints,
32 pub http: HTTPHints,
33 pub mcp: MCPHints,
34
35 #[allow(clippy::type_complexity)]
38 pub invoke: Box<dyn Fn(&Ctx, &JsonMap) -> errors::Result<Value> + Send + Sync>,
39}
40
41impl std::fmt::Debug for Entry {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 f.debug_struct("Entry")
44 .field("name", &self.name)
45 .field("input_schema", &self.input_schema)
46 .field("output_schema", &self.output_schema)
47 .field("cli", &self.cli)
48 .field("http", &self.http)
49 .field("mcp", &self.mcp)
50 .finish()
51 }
52}
53
54impl Entry {
55 pub(crate) fn _ty() {}
57
58 pub fn cli_defaults(&self) -> Map<String, Value> {
62 transport_defaults(&self.root, |f| f.cli.default.clone())
63 }
64
65 pub fn http_defaults(&self) -> Map<String, Value> {
67 transport_defaults(&self.root, |f| f.http.default.clone())
68 }
69
70 pub fn mcp_defaults(&self) -> Map<String, Value> {
72 transport_defaults(&self.root, |f| f.mcp.default.clone())
73 }
74}
75
76fn transport_defaults(
77 node: &FieldMeta,
78 get: impl Fn(&FieldMeta) -> Option<Value> + Copy,
79) -> Map<String, Value> {
80 let mut out = Map::new();
81 for f in &node.children {
82 if f.skip {
83 continue;
84 }
85 if let Some(d) = get(f) {
86 out.insert(f.json_name.clone(), d);
87 }
88 }
89 out
90}
91
92pub type SharedEntry = Arc<Entry>;