Skip to content

Commit f8fcb3a

Browse files
committed
feat(cli): add --http/--port/--host/--no-auth to serve, API key management to configure
1 parent 774fcca commit f8fcb3a

1 file changed

Lines changed: 93 additions & 3 deletions

File tree

src/main.rs

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,26 @@ enum Command {
9797
/// Register with an AI agent: "claude-code", "cursor", or "windsurf".
9898
#[arg(long)]
9999
register: Option<String>,
100+
101+
/// Generate and add a new API key.
102+
#[arg(long)]
103+
add_api_key: bool,
104+
105+
/// Name for the new API key (requires --add-api-key).
106+
#[arg(long, requires = "add_api_key")]
107+
key_name: Option<String>,
108+
109+
/// Permissions for the new key: "read" or "write" (requires --add-api-key).
110+
#[arg(long, requires = "add_api_key")]
111+
key_permissions: Option<String>,
112+
113+
/// List all API keys.
114+
#[arg(long)]
115+
list_api_keys: bool,
116+
117+
/// Revoke an API key by name.
118+
#[arg(long)]
119+
revoke_api_key: Option<String>,
100120
},
101121

102122
/// Manage embedding models.
@@ -106,7 +126,20 @@ enum Command {
106126
},
107127

108128
/// Start MCP stdio server for AI agent access.
109-
Serve,
129+
Serve {
130+
/// Enable HTTP REST API alongside MCP.
131+
#[arg(long)]
132+
http: bool,
133+
/// HTTP port (default: from config or 3000).
134+
#[arg(long)]
135+
port: Option<u16>,
136+
/// HTTP host to bind to (default: 127.0.0.1).
137+
#[arg(long)]
138+
host: Option<String>,
139+
/// Disable API key authentication (local development only, 127.0.0.1 only).
140+
#[arg(long)]
141+
no_auth: bool,
142+
},
110143

111144
/// Inspect vault graph connections.
112145
Graph {
@@ -618,6 +651,11 @@ async fn main() -> Result<()> {
618651
enable_obsidian_cli,
619652
disable_obsidian_cli,
620653
register,
654+
add_api_key,
655+
key_name,
656+
key_permissions,
657+
list_api_keys,
658+
revoke_api_key,
621659
} => {
622660
let mut cfg = Config::load()?;
623661

@@ -717,6 +755,48 @@ async fn main() -> Result<()> {
717755
}
718756
}
719757

758+
if add_api_key {
759+
let name = key_name.unwrap_or_else(|| "default".into());
760+
let perms = key_permissions.unwrap_or_else(|| "read".into());
761+
if perms != "read" && perms != "write" {
762+
anyhow::bail!("Permissions must be 'read' or 'write', got: {perms}");
763+
}
764+
let key = engraph::http::generate_api_key();
765+
cfg.http.api_keys.push(engraph::config::ApiKeyConfig {
766+
key: key.clone(),
767+
name: name.clone(),
768+
permissions: perms.clone(),
769+
});
770+
cfg.save()?;
771+
println!("API key created:");
772+
println!(" Name: {name}");
773+
println!(" Permissions: {perms}");
774+
println!(" Key: {key}");
775+
println!("\nSave this key — it won't be shown again.");
776+
}
777+
778+
if list_api_keys {
779+
if cfg.http.api_keys.is_empty() {
780+
println!("No API keys configured.");
781+
} else {
782+
println!("API keys:");
783+
for k in &cfg.http.api_keys {
784+
println!(" {} ({})", k.name, k.permissions);
785+
}
786+
}
787+
}
788+
789+
if let Some(ref name) = revoke_api_key {
790+
let before = cfg.http.api_keys.len();
791+
cfg.http.api_keys.retain(|k| k.name != *name);
792+
if cfg.http.api_keys.len() < before {
793+
cfg.save()?;
794+
println!("Revoked API key: {name}");
795+
} else {
796+
println!("No API key found with name: {name}");
797+
}
798+
}
799+
720800
cfg.save()?;
721801
println!(
722802
"Configuration saved to {}",
@@ -1051,12 +1131,22 @@ async fn main() -> Result<()> {
10511131
}
10521132
}
10531133

1054-
Command::Serve => {
1134+
Command::Serve { http, port, host, no_auth } => {
10551135
if !index_exists(&data_dir) {
10561136
eprintln!("No index found. Run 'engraph index <path>' first.");
10571137
std::process::exit(1);
10581138
}
1059-
engraph::serve::run_serve(&data_dir, None).await?;
1139+
let http_opts = if http {
1140+
let cfg = Config::load()?;
1141+
Some(engraph::serve::HttpServeOpts {
1142+
port: port.unwrap_or(cfg.http.port),
1143+
host: host.unwrap_or(cfg.http.host.clone()),
1144+
no_auth,
1145+
})
1146+
} else {
1147+
None
1148+
};
1149+
engraph::serve::run_serve(&data_dir, http_opts).await?;
10601150
}
10611151

10621152
Command::Write { action } => {

0 commit comments

Comments
 (0)