Skip to main content

qualia_client_core/api/
dashboard.rs

1//! Dashboard engine command
2
3#![allow(non_snake_case)]
4
5use super::*;
6
7use crate::qapp_registry;
8use crate::state::*;
9
10pub fn run_engine_command(cmd: String) -> String {
11    match cmd.as_str() {
12        "ingest_bench" => profile_energy_circumstance(),
13        "zk_screen" => format!(
14            "Daemon: {} | Ollama: {}",
15            daemon_status(),
16            check_ollama_status()
17        ),
18        _ => "Unknown command".to_string(),
19    }
20}
21
22// Tray functionality removed with Tauri
23
24pub fn toggle_window() {
25    // No-op without Tauri
26}
27
28// ─────────────────────────────────────────────────────────────────────────────
29// Agent Directory & Delegation Manager
30// ─────────────────────────────────────────────────────────────────────────────
31
32#[derive(Clone, serde::Serialize, serde::Deserialize)]
33pub struct DirectoryState {
34    pub actors: Vec<Actor>,
35    pub rules: Vec<DelegationRule>,
36    pub front_doors: Vec<FrontDoor>,
37    pub installed_qapps: Vec<qapp_registry::RegisteredQapp>,
38}
39
40#[derive(Clone, serde::Serialize, serde::Deserialize)]
41pub struct SignedDirectoryState {
42    pub state: DirectoryState,
43    pub signature_hex: String,
44}
45
46pub fn save_directory_state() {
47    let state = crate::state::APP_STATE.get().unwrap();
48    let home = std::env::var("USERPROFILE").unwrap_or_else(|_| "C:\\".to_string());
49    let qualia_dir = std::path::PathBuf::from(home).join(".qualia");
50    if !qualia_dir.exists() {
51        let _ = std::fs::create_dir_all(&qualia_dir);
52    }
53
54    let ds = DirectoryState {
55        actors: state.directory_actors.lock().unwrap().clone(),
56        rules: state.delegation_rules.lock().unwrap().clone(),
57        front_doors: state.front_doors.lock().unwrap().clone(),
58        installed_qapps: state.installed_qapps.lock().unwrap().clone(),
59    };
60
61    let payload = serde_json::to_string(&ds).unwrap();
62    let vault = state.key_vault.lock().unwrap();
63    // Since we don't have the derived key in scope here easily, we sign with master for persistence.
64    // In a real implementation, we'd sign with the specific identity.
65    let sig = vault.sign_payload(&vault.derive_key("persistence"), payload.as_bytes());
66    let sig_hex = hex::encode(sig.to_bytes());
67
68    let signed_state = SignedDirectoryState {
69        state: ds,
70        signature_hex: sig_hex,
71    };
72
73    let state_path = qualia_dir.join("directory_state.json");
74    let _ = std::fs::write(
75        &state_path,
76        serde_json::to_string_pretty(&signed_state).unwrap(),
77    );
78}
79
80pub fn load_directory_state(vault: &qualia_core_db::key_vault::KeyVault) -> DirectoryState {
81    let home = std::env::var("USERPROFILE").unwrap_or_else(|_| "C:\\".to_string());
82    let state_path = std::path::PathBuf::from(home)
83        .join(".qualia")
84        .join("directory_state.json");
85
86    if state_path.exists() {
87        if let Ok(content) = std::fs::read_to_string(&state_path) {
88            if let Ok(signed_state) = serde_json::from_str::<SignedDirectoryState>(&content) {
89                let payload = serde_json::to_string(&signed_state.state).unwrap();
90                let sig_bytes = hex::decode(&signed_state.signature_hex).unwrap_or_default();
91                if sig_bytes.len() == 64 {
92                    let mut sig_arr = [0u8; 64];
93                    sig_arr.copy_from_slice(&sig_bytes);
94                    let persistence_key = vault.derive_key("persistence");
95                    let pk = ed25519_dalek::VerifyingKey::from(&persistence_key);
96                    if qualia_core_db::key_vault::KeyVault::verify_signature(
97                        pk.as_bytes(),
98                        payload.as_bytes(),
99                        &sig_arr,
100                    )
101                    .is_ok()
102                    {
103                        return signed_state.state;
104                    } else {
105                        eprintln!("WARNING: directory_state.json signature validation failed! Tampering detected.");
106                    }
107                }
108            }
109        }
110    }
111
112    DirectoryState {
113        actors: Vec::new(),
114        rules: Vec::new(),
115        front_doors: Vec::new(),
116        installed_qapps: Vec::new(),
117    }
118}
119
120pub fn get_front_doors() -> Result<Vec<FrontDoor>, String> {
121    let state = crate::state::APP_STATE.get().unwrap();
122    let doors = state.front_doors.lock().unwrap().clone();
123    Ok(doors)
124}
125
126pub fn generate_front_door(label: String) -> Result<FrontDoor, String> {
127    let state = crate::state::APP_STATE.get().unwrap();
128    use std::time::{SystemTime, UNIX_EPOCH};
129    let now = SystemTime::now()
130        .duration_since(UNIX_EPOCH)
131        .unwrap()
132        .as_millis();
133
134    let vault = state.key_vault.lock().unwrap();
135    let fd_id = format!("fd-{}", now);
136    let derived_key = vault.derive_key(&fd_id);
137    let pub_key_hex = hex::encode(ed25519_dalek::VerifyingKey::from(&derived_key).as_bytes());
138    let did_uri = format!("did:qualia:frontdoor:{}", pub_key_hex);
139
140    // Optional: Pre-generate the WebID-TLS cert here if needed
141    // let (cert, _) = vault.generate_webid_tls_cert(&derived_key, &did_uri).unwrap();
142
143    let door = FrontDoor {
144        id: fd_id,
145        did_uri,
146        label,
147        created_at: now.to_string(),
148        routing_hints: vec![],
149    };
150
151    drop(vault);
152    state.front_doors.lock().unwrap().push(door.clone());
153    save_directory_state();
154    Ok(door)
155}
156
157pub fn get_directory_actors() -> Result<Vec<Actor>, String> {
158    let state = crate::state::APP_STATE.get().unwrap();
159    let actors = state.directory_actors.lock().unwrap().clone();
160    Ok(actors)
161}
162
163pub fn add_directory_actor(actor: Actor) -> Result<(), String> {
164    let state = crate::state::APP_STATE.get().unwrap();
165    state.directory_actors.lock().unwrap().push(actor);
166    save_directory_state();
167    Ok(())
168}
169
170pub fn get_delegation_rules() -> Result<Vec<DelegationRule>, String> {
171    let state = crate::state::APP_STATE.get().unwrap();
172    let rules = state.delegation_rules.lock().unwrap().clone();
173    Ok(rules)
174}
175
176pub fn add_delegation_rule(rule: DelegationRule) -> Result<(), String> {
177    let state = crate::state::APP_STATE.get().unwrap();
178    state.delegation_rules.lock().unwrap().push(rule);
179    save_directory_state();
180    Ok(())
181}