use clap::{Parser, Subcommand};
use serde_json::Value;
#[derive(Parser)]
#[command(name = "tempus-ddb-core")]
#[command(about = "Tempus DDB Core - INTERNAL DEV CLI (Use the Python `tempus` CLI for production)", long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Init {
#[arg(long, default_value = "tempus.db")]
db: String,
},
GenKeys {
#[arg(long, default_value = "keys.json")]
output: String,
},
Record {
#[arg(long, default_value = "tempus.db")]
db: String,
#[arg(long)]
payload: String,
#[arg(long)]
rules: String,
#[arg(long, default_value = "keys.json")]
keyfile: String,
#[arg(long)]
genesis: bool,
},
Validate {
#[arg(long, default_value = "tempus.db")]
db: String,
},
Export {
#[arg(long, default_value = "tempus.db")]
db: String,
},
List {
#[arg(long, default_value = "tempus.db")]
db: String,
#[arg(long, default_value = "10")]
limit: u32,
#[arg(long, default_value = "0")]
offset: u32,
},
Count {
#[arg(long, default_value = "tempus.db")]
db: String,
},
RegisterAgent {
#[arg(long, default_value = "tempus.db")]
db: String,
#[arg(long, default_value = "gate.keys.json")]
keyfile: String,
#[arg(long, alias = "public-key")]
public_key: String,
#[arg(long)]
alias: String,
#[arg(long, default_value = "{}")]
metadata: String,
},
ListAgents {
#[arg(long, default_value = "tempus.db")]
db: String,
},
RequestAction {
#[arg(long, default_value = "tempus.db")]
db: String,
#[arg(long, default_value = "gate.keys.json")]
gate_keyfile: String,
#[arg(long)]
agent_keyfile: String,
#[arg(long)]
intent: String,
#[arg(long, default_value = "60")]
ttl_seconds: u64,
},
CommitOutcome {
#[arg(long, default_value = "tempus.db")]
db: String,
#[arg(long, default_value = "gate.keys.json")]
gate_keyfile: String,
#[arg(long)]
authorization_id: String,
#[arg(long)]
outcome: String,
#[arg(long)]
executor_keyfile: String,
},
Trace {
#[arg(long, default_value = "tempus.db")]
db: String,
#[arg(long, default_value = "gate.keys.json")]
gate_keyfile: String,
#[arg(long)]
action_id: String,
},
VerifyTrace {
#[arg(long, default_value = "tempus.db")]
db: String,
#[arg(long, default_value = "gate.keys.json")]
gate_keyfile: String,
#[arg(long)]
action_id: String,
},
}
fn main() {
let cli = Cli::parse();
match cli.command {
Commands::Init { db } => {
match _tempus_ddb::SqliteStorage::new(db.clone(), "keys.json".to_string()) {
Ok(_) => eprintln!("Database initialized successfully: {}", db),
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}
}
Commands::GenKeys { output } => match _tempus_ddb::generate_keypair(&output) {
Ok(json_str) => {
eprintln!("Cryptographic keys generated and saved to: {}", output);
let val: Value = serde_json::from_str(&json_str).unwrap();
println!(
"{}",
serde_json::to_string(&serde_json::json!({
"public_key": val.get("public_key")
}))
.unwrap()
);
}
Err(e) => {
eprintln!("Error generating keys: {}", e);
std::process::exit(1);
}
},
Commands::Record {
db,
payload,
rules,
keyfile,
genesis,
} => {
let mut storage = match _tempus_ddb::SqliteStorage::new(db, keyfile) {
Ok(s) => s,
Err(e) => {
eprintln!("Error opening database: {}", e);
std::process::exit(1);
}
};
use _tempus_ddb::StorageLayer;
if let Err(e) = storage.insert_decision(&payload, &rules, genesis) {
eprintln!("Error recording decision: {}", e);
std::process::exit(1);
}
let latest = storage.get_latest_hash().unwrap_or_default();
println!(
"{}",
serde_json::to_string(&serde_json::json!({
"status": "success",
"action": "recorded",
"latest_hash": latest
}))
.unwrap()
);
}
Commands::Validate { db } => {
let storage = match _tempus_ddb::SqliteStorage::new(db, "keys.json".to_string()) {
Ok(s) => s,
Err(e) => {
eprintln!("Error opening database: {}", e);
std::process::exit(1);
}
};
match storage.validate_ledger() {
Ok(json) => println!("{}", json),
Err(e) => {
println!("{}", e);
std::process::exit(1);
}
}
}
Commands::Export { db } => {
let storage = match _tempus_ddb::SqliteStorage::new(db, "keys.json".to_string()) {
Ok(s) => s,
Err(e) => {
eprintln!("Error opening database: {}", e);
std::process::exit(1);
}
};
use _tempus_ddb::StorageLayer;
match storage.export_ledger() {
Ok(json) => println!("{}", json),
Err(e) => {
eprintln!("Error exporting ledger: {}", e);
std::process::exit(1);
}
}
}
Commands::List { db, limit, offset } => {
let storage = match _tempus_ddb::SqliteStorage::new(db, "keys.json".to_string()) {
Ok(s) => s,
Err(e) => {
eprintln!("Error opening database: {}", e);
std::process::exit(1);
}
};
use _tempus_ddb::StorageLayer;
match storage.list_decisions(limit, offset) {
Ok(json) => println!("{}", json),
Err(e) => {
eprintln!("Error listing decisions: {}", e);
std::process::exit(1);
}
}
}
Commands::Count { db } => {
let storage = match _tempus_ddb::SqliteStorage::new(db, "keys.json".to_string()) {
Ok(s) => s,
Err(e) => {
eprintln!("Error opening database: {}", e);
std::process::exit(1);
}
};
use _tempus_ddb::StorageLayer;
match storage.count_decisions() {
Ok(count) => println!(
"{}",
serde_json::to_string(&serde_json::json!({
"total_decisions": count
}))
.unwrap()
),
Err(e) => {
eprintln!("Error counting decisions: {}", e);
std::process::exit(1);
}
}
}
Commands::RegisterAgent {
db,
keyfile,
public_key,
alias,
metadata,
} => {
let storage = match _tempus_ddb::SqliteStorage::new(db, keyfile) {
Ok(s) => s,
Err(e) => {
eprintln!("Error opening database: {}", e);
std::process::exit(1);
}
};
match storage.register_agent(&public_key, &alias, &metadata) {
Ok(json) => println!("{}", json),
Err(e) => {
eprintln!("Error registering agent: {}", e);
std::process::exit(1);
}
}
}
Commands::ListAgents { db } => {
let storage = match _tempus_ddb::SqliteStorage::new(db, "keys.json".to_string()) {
Ok(s) => s,
Err(e) => {
eprintln!("Error opening database: {}", e);
std::process::exit(1);
}
};
match storage.list_agents() {
Ok(json) => println!("{}", json),
Err(e) => {
eprintln!("Error listing agents: {}", e);
std::process::exit(1);
}
}
}
Commands::RequestAction {
db,
gate_keyfile,
agent_keyfile,
intent,
ttl_seconds,
} => {
let storage = match _tempus_ddb::SqliteStorage::new(db, gate_keyfile) {
Ok(storage) => storage,
Err(error) => {
eprintln!("Error opening gate: {error}");
std::process::exit(1);
}
};
match storage.request_action(&intent, &agent_keyfile, ttl_seconds) {
Ok(json) => println!("{json}"),
Err(error) => {
eprintln!("Error requesting action: {error}");
std::process::exit(1);
}
}
}
Commands::CommitOutcome {
db,
gate_keyfile,
authorization_id,
outcome,
executor_keyfile,
} => {
let storage = match _tempus_ddb::SqliteStorage::new(db, gate_keyfile) {
Ok(storage) => storage,
Err(error) => {
eprintln!("Error opening gate: {error}");
std::process::exit(1);
}
};
match storage.commit_outcome(&authorization_id, &outcome, &executor_keyfile) {
Ok(json) => println!("{json}"),
Err(error) => {
eprintln!("Error committing outcome: {error}");
std::process::exit(1);
}
}
}
Commands::Trace {
db,
gate_keyfile,
action_id,
} => {
let storage = match _tempus_ddb::SqliteStorage::new(db, gate_keyfile) {
Ok(storage) => storage,
Err(error) => {
eprintln!("Error opening gate: {error}");
std::process::exit(1);
}
};
match storage.get_trace(&action_id) {
Ok(json) => println!("{json}"),
Err(error) => {
eprintln!("Error reading trace: {error}");
std::process::exit(1);
}
}
}
Commands::VerifyTrace {
db,
gate_keyfile,
action_id,
} => {
let storage = match _tempus_ddb::SqliteStorage::new(db, gate_keyfile) {
Ok(storage) => storage,
Err(error) => {
eprintln!("Error opening gate: {error}");
std::process::exit(1);
}
};
match storage.verify_trace(&action_id) {
Ok(json) => {
println!("{json}");
if json.contains("\"status\":\"INVALID\"") {
std::process::exit(2);
}
}
Err(error) => {
eprintln!("Error verifying trace: {error}");
std::process::exit(1);
}
}
}
}
}