Skip to content

Commit ace5aa9

Browse files
committed
tauri: wire diagnostics/fixes/onboarding/templates/send/bot IPC commands desktop src-tauri:
- New commands: bot.rs, diagnostics.rs, fixes.rs, heartbeat.rs, onboarding.rs, send.rs, sessions.rs, templates.rs — all delegate to the springtaled HTTP API. - New runtime_guard.rs: ensures daemon is running before IPC calls. - state.rs: refactored to hold runtime connection + guard state. - lib.rs: register all new commands in the Tauri handler. - Existing commands (agent, authors, canvas, config, connectors, data, events, formations, memory, panic, rules, safety, travel, vault) updated for consistent error handling and new API shapes. desktop frontend: - New ipc/: diagnostics.ts, fixes.ts, onboarding.ts, send.ts, templates.ts. - provider.ts + App.tsx: integrate new IPC surfaces. dashboard: - provider.ts: HTTP provider gains the new endpoint wrappers. packages: - types/operations.ts: shared TypeScript types for the new operations. - types/index.ts + dashboard/types.ts: re-exports and DataProvider interface expanded.
1 parent f0c8c25 commit ace5aa9

38 files changed

Lines changed: 959 additions & 180 deletions

tauri/apps/dashboard/src/provider.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
* response envelopes ({ connectors: [...] } → [...]).
66
*/
77
import type { DataProvider } from "@springtale/ui";
8-
import type { ConnectorSchema, EventEntry, AvailableConnector } from "@springtale/types";
8+
import type {
9+
ConnectorSchema, EventEntry, AvailableConnector,
10+
Report, PlatformForm, ApplyReport, Template, WriteReport,
11+
FixGuide, FixOutcome, SendRequest, SendOutcome,
12+
} from "@springtale/types";
913
import type { RuleSummary, FormationInfo } from "@springtale/ui";
1014
import { get, post, put, del, getBaseUrl, getToken } from "./api/client";
1115
import { subscribeToEvents } from "./api/events";
@@ -149,5 +153,45 @@ export function createWebProvider(): DataProvider {
149153
if (!token) return () => {};
150154
return subscribeToCanvasUpdates(getBaseUrl(), token, callback);
151155
},
156+
157+
// Diagnostics
158+
async runDiagnostics() {
159+
return get<Report>("/diagnostics");
160+
},
161+
162+
// Onboarding
163+
async listOnboardingPlatforms() {
164+
const data = await get<{ platforms: PlatformForm[] }>("/onboarding/platforms");
165+
return data.platforms ?? [];
166+
},
167+
async applyOnboarding(platform, answers) {
168+
return post<ApplyReport>("/onboarding/apply", { platform, answers });
169+
},
170+
171+
// Templates
172+
async listTemplates() {
173+
const data = await get<{ templates: Template[] }>("/templates");
174+
return data.templates ?? [];
175+
},
176+
async writeTemplate(name) {
177+
return post<WriteReport>("/templates/write", { name });
178+
},
179+
180+
// Error fixes
181+
async listFixes() {
182+
const data = await get<{ guides: FixGuide[] }>("/fixes");
183+
return data.guides ?? [];
184+
},
185+
async getFix(id) {
186+
return get<FixGuide>(`/fixes/${id}`);
187+
},
188+
async applyFix(id) {
189+
return post<FixOutcome>(`/fixes/${id}/apply`);
190+
},
191+
192+
// Cross-channel send
193+
async sendMessage(req) {
194+
return post<SendOutcome>("/send", req);
195+
},
152196
};
153197
}

tauri/apps/desktop/src-tauri/Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tauri/apps/desktop/src-tauri/src/commands/agent.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
use tauri::State;
22

3+
use crate::runtime_guard::require_runtime;
34
use crate::state::AppState;
45

56
/// List aggregated agent states (rules + events + autonomy).
67
#[tauri::command]
78
pub async fn list_agent_states(
89
state: State<'_, AppState>,
910
) -> Result<Vec<springtale_runtime::operations::agent::AgentState>, String> {
10-
springtale_runtime::operations::agent::list_agent_states(&state.runtime)
11+
let guard = require_runtime(&state.runtime).await?;
12+
let rt = guard.as_ref().unwrap();
13+
springtale_runtime::operations::agent::list_agent_states(rt)
1114
.await
1215
.map_err(|e| e.to_string())
1316
}
@@ -18,7 +21,9 @@ pub async fn get_autonomy(
1821
state: State<'_, AppState>,
1922
name: String,
2023
) -> Result<String, String> {
21-
springtale_runtime::operations::agent::get_autonomy(&*state.runtime.store, &name)
24+
let guard = require_runtime(&state.runtime).await?;
25+
let rt = guard.as_ref().unwrap();
26+
springtale_runtime::operations::agent::get_autonomy(&*rt.store, &name)
2227
.await
2328
.map_err(|e| e.to_string())
2429
}
@@ -30,7 +35,9 @@ pub async fn set_autonomy(
3035
name: String,
3136
level: String,
3237
) -> Result<(), String> {
33-
springtale_runtime::operations::agent::set_autonomy(&*state.runtime.store, &name, &level)
38+
let guard = require_runtime(&state.runtime).await?;
39+
let rt = guard.as_ref().unwrap();
40+
springtale_runtime::operations::agent::set_autonomy(&*rt.store, &name, &level)
3441
.await
3542
.map_err(|e| e.to_string())
3643
}
@@ -42,7 +49,9 @@ pub async fn step_autonomy(
4249
name: String,
4350
direction: springtale_runtime::operations::agent::AutonomyDirection,
4451
) -> Result<String, String> {
45-
springtale_runtime::operations::agent::step_autonomy(&*state.runtime.store, &name, direction)
52+
let guard = require_runtime(&state.runtime).await?;
53+
let rt = guard.as_ref().unwrap();
54+
springtale_runtime::operations::agent::step_autonomy(&*rt.store, &name, direction)
4655
.await
4756
.map_err(|e| e.to_string())
4857
}

tauri/apps/desktop/src-tauri/src/commands/authors.rs

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
use tauri::State;
22

3+
use crate::runtime_guard::require_runtime;
34
use crate::state::AppState;
45

56
/// List all trusted authors.
67
#[tauri::command]
7-
pub async fn list_authors(
8-
state: State<'_, AppState>,
9-
) -> Result<serde_json::Value, String> {
10-
let configs = state
11-
.runtime
12-
.store
13-
.list_config()
14-
.await
15-
.map_err(|e| e.to_string())?;
8+
pub async fn list_authors(state: State<'_, AppState>) -> Result<serde_json::Value, String> {
9+
let guard = require_runtime(&state.runtime).await?;
10+
let rt = guard.as_ref().unwrap();
11+
let configs = rt.store.list_config().await.map_err(|e| e.to_string())?;
1612

1713
let authors: Vec<serde_json::Value> = configs
1814
.into_iter()
@@ -36,32 +32,29 @@ pub async fn add_author(
3632
name: String,
3733
pubkey: String,
3834
) -> Result<(), String> {
39-
// Validate pubkey is valid hex and 32 bytes
35+
let guard = require_runtime(&state.runtime).await?;
36+
let rt = guard.as_ref().unwrap();
37+
4038
let bytes = hex::decode(&pubkey).map_err(|e| format!("invalid pubkey hex: {e}"))?;
4139
if bytes.len() != 32 {
4240
return Err("pubkey must be 32 bytes (64 hex chars)".into());
4341
}
4442

4543
let key = format!("trusted-author:{name}");
4644
let value = serde_json::json!({ "pubkey": pubkey }).to_string();
47-
state
48-
.runtime
49-
.store
45+
rt.store
5046
.set_config(&key, &value)
5147
.await
5248
.map_err(|e| e.to_string())
5349
}
5450

5551
/// Remove a trusted author.
5652
#[tauri::command]
57-
pub async fn remove_author(
58-
state: State<'_, AppState>,
59-
name: String,
60-
) -> Result<(), String> {
53+
pub async fn remove_author(state: State<'_, AppState>, name: String) -> Result<(), String> {
54+
let guard = require_runtime(&state.runtime).await?;
55+
let rt = guard.as_ref().unwrap();
6156
let key = format!("trusted-author:{name}");
62-
state
63-
.runtime
64-
.store
57+
rt.store
6558
.delete_config(&key)
6659
.await
6760
.map_err(|e| e.to_string())
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use tauri::State;
2+
3+
use crate::runtime_guard::require_runtime;
4+
use crate::state::AppState;
5+
6+
/// Get bot status: running state, connector/rule/formation counts.
7+
#[tauri::command]
8+
pub async fn bot_status(state: State<'_, AppState>) -> Result<serde_json::Value, String> {
9+
let guard = require_runtime(&state.runtime).await?;
10+
let rt = guard.as_ref().unwrap();
11+
12+
let registry = rt.registry.read().await;
13+
let connector_count = registry.list().len();
14+
drop(registry);
15+
16+
let engine = rt.engine.read().await;
17+
let rule_count = engine.list_rules().len();
18+
drop(engine);
19+
20+
let formation_count = rt
21+
.store
22+
.list_formations()
23+
.await
24+
.map(|f| f.len())
25+
.unwrap_or(0);
26+
27+
Ok(serde_json::json!({
28+
"running": true,
29+
"connectors": connector_count,
30+
"rules": rule_count,
31+
"formations": formation_count,
32+
}))
33+
}
34+
35+
/// Get bot memory stats (session count).
36+
#[tauri::command]
37+
pub async fn bot_memory(state: State<'_, AppState>) -> Result<serde_json::Value, String> {
38+
let guard = require_runtime(&state.runtime).await?;
39+
let rt = guard.as_ref().unwrap();
40+
let sessions = rt.store.list_sessions().await.map_err(|e| e.to_string())?;
41+
Ok(serde_json::json!({
42+
"session_count": sessions.len(),
43+
}))
44+
}

tauri/apps/desktop/src-tauri/src/commands/canvas.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,27 @@ use tauri::State;
22

33
use springtale_core::canvas::{CanvasState, CanvasUpdate};
44

5+
use crate::runtime_guard::require_runtime;
56
use crate::state::AppState;
67

78
/// Get computed connection graph.
89
#[tauri::command]
910
pub async fn get_connections(
1011
state: State<'_, AppState>,
1112
) -> Result<Vec<springtale_runtime::operations::canvas::Connection>, String> {
12-
springtale_runtime::operations::canvas::compute_connections(&state.runtime)
13+
let guard = require_runtime(&state.runtime).await?;
14+
let rt = guard.as_ref().unwrap();
15+
springtale_runtime::operations::canvas::compute_connections(rt)
1316
.await
1417
.map_err(|e| e.to_string())
1518
}
1619

1720
/// Get the current canvas state snapshot.
1821
#[tauri::command]
1922
pub async fn get_canvas_state(state: State<'_, AppState>) -> Result<CanvasState, String> {
20-
Ok(springtale_runtime::operations::canvas::get_canvas(&state.runtime).await)
23+
let guard = require_runtime(&state.runtime).await?;
24+
let rt = guard.as_ref().unwrap();
25+
Ok(springtale_runtime::operations::canvas::get_canvas(rt).await)
2126
}
2227

2328
/// Apply a canvas update.
@@ -26,5 +31,7 @@ pub async fn update_canvas(
2631
state: State<'_, AppState>,
2732
update: CanvasUpdate,
2833
) -> Result<CanvasState, String> {
29-
Ok(springtale_runtime::operations::canvas::update_canvas(&state.runtime, update).await)
34+
let guard = require_runtime(&state.runtime).await?;
35+
let rt = guard.as_ref().unwrap();
36+
Ok(springtale_runtime::operations::canvas::update_canvas(rt, update).await)
3037
}

tauri/apps/desktop/src-tauri/src/commands/config.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use tauri::State;
22

3+
use crate::runtime_guard::require_runtime;
34
use crate::state::AppState;
45

56
/// Get a config value by key.
@@ -8,7 +9,9 @@ pub async fn get_config(
89
state: State<'_, AppState>,
910
key: String,
1011
) -> Result<serde_json::Value, String> {
11-
springtale_runtime::operations::config::get_config(&*state.runtime.store, &key)
12+
let guard = require_runtime(&state.runtime).await?;
13+
let rt = guard.as_ref().unwrap();
14+
springtale_runtime::operations::config::get_config(&*rt.store, &key)
1215
.await
1316
.map_err(|e| e.to_string())
1417
}
@@ -20,7 +23,9 @@ pub async fn set_config(
2023
key: String,
2124
value: serde_json::Value,
2225
) -> Result<(), String> {
23-
springtale_runtime::operations::config::set_config(&*state.runtime.store, &key, value)
26+
let guard = require_runtime(&state.runtime).await?;
27+
let rt = guard.as_ref().unwrap();
28+
springtale_runtime::operations::config::set_config(&*rt.store, &key, value)
2429
.await
2530
.map_err(|e| e.to_string())
2631
}
@@ -30,7 +35,9 @@ pub async fn set_config(
3035
pub async fn list_config(
3136
state: State<'_, AppState>,
3237
) -> Result<Vec<(String, serde_json::Value)>, String> {
33-
springtale_runtime::operations::config::list_config(&*state.runtime.store)
38+
let guard = require_runtime(&state.runtime).await?;
39+
let rt = guard.as_ref().unwrap();
40+
springtale_runtime::operations::config::list_config(&*rt.store)
3441
.await
3542
.map_err(|e| e.to_string())
3643
}
@@ -41,7 +48,9 @@ pub async fn set_ai_adapter(
4148
state: State<'_, AppState>,
4249
config: serde_json::Value,
4350
) -> Result<(), String> {
44-
springtale_runtime::operations::config::set_ai_adapter(&state.runtime, config)
51+
let guard = require_runtime(&state.runtime).await?;
52+
let rt = guard.as_ref().unwrap();
53+
springtale_runtime::operations::config::set_ai_adapter(rt, config)
4554
.await
4655
.map_err(|e| e.to_string())
4756
}
@@ -53,7 +62,9 @@ pub async fn set_connector_config(
5362
name: String,
5463
config: serde_json::Value,
5564
) -> Result<(), String> {
56-
springtale_runtime::operations::config::set_connector_config(&state.runtime, &name, config)
65+
let guard = require_runtime(&state.runtime).await?;
66+
let rt = guard.as_ref().unwrap();
67+
springtale_runtime::operations::config::set_connector_config(rt, &name, config)
5768
.await
5869
.map_err(|e| e.to_string())
5970
}
@@ -65,7 +76,9 @@ pub async fn configure_ai_adapter(
6576
target: String,
6677
config: serde_json::Value,
6778
) -> Result<(), String> {
68-
springtale_runtime::operations::config::configure_ai_adapter(&state.runtime, &target, config)
79+
let guard = require_runtime(&state.runtime).await?;
80+
let rt = guard.as_ref().unwrap();
81+
springtale_runtime::operations::config::configure_ai_adapter(rt, &target, config)
6982
.await
7083
.map_err(|e| e.to_string())
7184
}
@@ -77,7 +90,9 @@ pub async fn upsert_connector_config(
7790
name: String,
7891
config: serde_json::Value,
7992
) -> Result<bool, String> {
80-
springtale_runtime::operations::config::upsert_connector_config(&state.runtime, &name, config)
93+
let guard = require_runtime(&state.runtime).await?;
94+
let rt = guard.as_ref().unwrap();
95+
springtale_runtime::operations::config::upsert_connector_config(rt, &name, config)
8196
.await
8297
.map_err(|e| e.to_string())
8398
}
@@ -88,7 +103,9 @@ pub async fn toggle_formation_guard(
88103
state: State<'_, AppState>,
89104
formation_id: String,
90105
) -> Result<bool, String> {
91-
springtale_runtime::operations::config::toggle_formation_guard(&state.runtime, &formation_id)
106+
let guard = require_runtime(&state.runtime).await?;
107+
let rt = guard.as_ref().unwrap();
108+
springtale_runtime::operations::config::toggle_formation_guard(rt, &formation_id)
92109
.await
93110
.map_err(|e| e.to_string())
94111
}

0 commit comments

Comments
 (0)