aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-06-29 22:58:18 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-06-29 22:58:34 +0300
commit6703413fc7ef864f102aa2de5840bf874b589101 (patch)
treedc4314024f4627e41fd009efb22fb013e0836de6 /src
parent09bac7f274a2944ca5a5ed83d11845ca6b0ce960 (diff)
feat: expose api schema from cli
Diffstat (limited to 'src')
-rw-r--r--src/cli.rs2
-rw-r--r--src/cli/api.rs102
-rw-r--r--src/main.rs5
3 files changed, 109 insertions, 0 deletions
diff --git a/src/cli.rs b/src/cli.rs
index 3facba8b..0e0daf54 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -9,6 +9,7 @@ use crate::api::schema::{
};
mod agent;
+mod api;
mod integration;
mod notification;
mod pane;
@@ -49,6 +50,7 @@ pub fn maybe_run(args: &[String]) -> std::io::Result<CommandOutcome> {
};
exit_code
}
+ "api" => api::run_api_command(&args[2..])?,
"status" => status::run_status_command(&args[2..])?,
"config" => run_config_command(&args[2..])?,
"channel" => run_channel_command(&args[2..])?,
diff --git a/src/cli/api.rs b/src/cli/api.rs
new file mode 100644
index 00000000..e931f4f8
--- /dev/null
+++ b/src/cli/api.rs
@@ -0,0 +1,102 @@
+const API_SCHEMA_JSON: &str = include_str!("../../docs/next/api/herdr-api.schema.json");
+
+pub(super) fn run_api_command(args: &[String]) -> std::io::Result<i32> {
+ let Some(subcommand) = args.first().map(String::as_str) else {
+ print_api_help();
+ return Ok(2);
+ };
+
+ match subcommand {
+ "schema" => api_schema(&args[1..]),
+ "help" | "--help" | "-h" => {
+ print_api_help();
+ Ok(0)
+ }
+ _ => {
+ print_api_help();
+ Ok(2)
+ }
+ }
+}
+
+fn api_schema(args: &[String]) -> std::io::Result<i32> {
+ match args {
+ [] => {
+ print!("{}", schema_summary_text()?);
+ }
+ [flag] if flag == "--json" => {
+ print!("{API_SCHEMA_JSON}");
+ }
+ [flag, path] if flag == "--output" => {
+ write_schema_file(std::path::Path::new(path))?;
+ println!("wrote API schema to {path}");
+ }
+ [flag] if flag == "--output" => {
+ eprintln!("missing value for --output");
+ return Ok(2);
+ }
+ [flag] if matches!(flag.as_str(), "help" | "--help" | "-h") => {
+ print_api_schema_help();
+ }
+ [other] if other.starts_with('-') => {
+ eprintln!("unknown option: {other}");
+ return Ok(2);
+ }
+ _ => {
+ print_api_schema_help();
+ return Ok(2);
+ }
+ }
+ Ok(0)
+}
+
+fn write_schema_file(path: &std::path::Path) -> std::io::Result<()> {
+ std::fs::write(path, API_SCHEMA_JSON)
+}
+
+fn schema_summary_text() -> std::io::Result<String> {
+ let value: serde_json::Value = serde_json::from_str(API_SCHEMA_JSON)?;
+ let protocol = value
+ .get("protocol")
+ .and_then(serde_json::Value::as_u64)
+ .ok_or_else(|| std::io::Error::other("API schema is missing protocol"))?;
+ let schema_version = value
+ .get("schema_version")
+ .and_then(serde_json::Value::as_u64)
+ .ok_or_else(|| std::io::Error::other("API schema is missing schema_version"))?;
+ let mut schemas: Vec<&str> = value
+ .get("schemas")
+ .and_then(serde_json::Value::as_object)
+ .ok_or_else(|| std::io::Error::other("API schema is missing schemas"))?
+ .keys()
+ .map(String::as_str)
+ .collect();
+ schemas.sort();
+
+ Ok(format!(
+ "Herdr API schema\nprotocol: {}\nschema_version: {}\nschemas: {}\n\nUse `herdr api schema --json` to print the full schema.\nUse `herdr api schema --output PATH` to write it to a file.\n",
+ protocol,
+ schema_version,
+ schemas.join(", ")
+ ))
+}
+
+fn print_api_help() {
+ eprintln!("herdr api commands:");
+ eprintln!(" herdr api schema [--json | --output PATH]");
+}
+
+fn print_api_schema_help() {
+ eprintln!("usage: herdr api schema [--json | --output PATH]");
+}
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn schema_summary_text_stays_human_sized() {
+ let text = super::schema_summary_text().unwrap();
+ assert!(text.contains("Herdr API schema"));
+ assert!(text.contains("Use `herdr api schema --json`"));
+ assert!(text.len() < 400);
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 597b332e..ea46585f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -486,6 +486,7 @@ fn main() -> io::Result<()> {
println!(" herdr channel set <stable|preview>");
println!(" herdr server stop");
println!(" herdr server reload-config");
+ println!(" herdr api <subcommand> ...");
println!(" herdr config <subcommand> ...");
println!(" herdr channel <subcommand> ...");
println!(" herdr workspace <subcommand> ...");
@@ -527,6 +528,10 @@ fn main() -> io::Result<()> {
"Manage the stable or preview update channel",
),
(
+ "herdr api <subcommand>",
+ "Inspect the bundled socket API schema",
+ ),
+ (
"herdr workspace <subcommand>",
"Workspace helpers over the socket API",
),