Skip to content

Commit 8094314

Browse files
hyperpolymathclaude
andcommitted
fix(gossamer): wire groove server + llm_coding command surface
Closes #17 — groove discovery server is launched once at startup via groove::spawn() before the webview opens. spawn() also starts the mesh-monitor thread internally, so peers in the mesh (Burble, Vext, Hypatia, VeriSimDB) can probe `/.well-known/groove` on 127.0.0.1:8000 for the entire app lifetime. The previous commented-out groove_discover/groove_status command shims were architecturally wrong: groove is an *external* discovery surface, not something the local webview needs to call into itself. Replaced with a comment explaining where groove actually lives. Closes #18 — llm_coding gets nine real app.command registrations matching the actual `llm_coding_*` API in src-gossamer/src/llm_coding/ commands.rs: llm_coding_init / llm_coding_spawn / llm_coding_freeze / llm_coding_thaw / llm_coding_terminate / llm_coding_list_sessions / llm_coding_session_status / llm_coding_append_message / llm_coding_get_messages The pre-Tauri→gossamer-rs commented-out block called start_session, stop_session, session_status, list_sessions — none of which exist. llm_coding_spawn deserialises a SpawnRequest struct via serde_json::from_value so payloads keep their typed shape. Adds result_str_to_json helper next to result_to_json to avoid double-encoding: the llm_coding_* functions return Result<String, String> where the String is itself JSON, so the helper parses it before wrapping in `{"ok": true, "result": <object>}`. cargo check + cargo test --no-run clean. The 15 unused-function warnings in settings.rs are pre-existing and out of scope. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 078c179 commit 8094314

1 file changed

Lines changed: 73 additions & 25 deletions

File tree

src-gossamer/src/main.rs

Lines changed: 73 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,18 @@ fn result_to_json<T: serde::Serialize>(result: Result<T, String>) -> Result<serd
7979
}
8080
}
8181

82+
// Wrap a Result whose Ok variant is itself a JSON-encoded string,
83+
// so the response is `{"ok": true, "result": <object>}` instead of a
84+
// string-wrapped string the client would have to parse twice.
85+
fn result_str_to_json(result: Result<String, String>) -> Result<serde_json::Value, String> {
86+
match result {
87+
Ok(s) => result_to_json(Ok(
88+
serde_json::from_str::<serde_json::Value>(&s).unwrap_or(serde_json::Value::Null),
89+
)),
90+
Err(e) => result_to_json::<serde_json::Value>(Err(e)),
91+
}
92+
}
93+
8294
fn blocking_get(url: &str, timeout_secs: u64) -> Result<String, String> {
8395
let client = reqwest::blocking::Client::builder()
8496
.timeout(std::time::Duration::from_secs(timeout_secs))
@@ -123,6 +135,13 @@ fn blocking_post_empty(url: &str, timeout_secs: u64) -> Result<String, String> {
123135
// -----------------------------------------------------------------------
124136

125137
fn main() {
138+
// Spawn the groove discovery server (HTTP on 127.0.0.1:8000) on its own
139+
// thread before the webview starts. This lets peers in the mesh
140+
// (Burble, Vext, Hypatia, VeriSimDB) probe `/.well-known/groove` and
141+
// discover PanLL's panel-ui capability for the entire app lifetime.
142+
// `spawn()` also starts the mesh-monitor thread internally.
143+
groove::spawn();
144+
126145
// Initialize Gossamer app
127146
let app = App::new("PanLL", 1280, 800);
128147

@@ -140,37 +159,66 @@ fn register_commands(app: &mut gossamer_rs::App) {
140159
// LLM Coding commands
141160
// -----------------------------------------------------------------------
142161

143-
// app.command("llm_coding_start", |payload| {
144-
// let session_id = get_str(&payload, "session_id").unwrap_or_default();
145-
// let prompt = get_str(&payload, "prompt").unwrap_or_default();
146-
// result_to_json(llm_coding::start_session(session_id, prompt))
147-
// });
162+
app.command("llm_coding_init", |_payload| {
163+
result_str_to_json(llm_coding::commands::llm_coding_init())
164+
});
148165

149-
// app.command("llm_coding_stop", |payload| {
150-
// let session_id = get_str(&payload, "session_id").unwrap_or_default();
151-
// result_to_json(llm_coding::stop_session(session_id))
152-
// });
166+
app.command("llm_coding_spawn", |payload: serde_json::Value| {
167+
match serde_json::from_value::<llm_coding::types::SpawnRequest>(payload) {
168+
Ok(request) => result_str_to_json(llm_coding::commands::llm_coding_spawn(request)),
169+
Err(e) => result_to_json::<serde_json::Value>(Err(format!(
170+
"Invalid SpawnRequest payload: {}",
171+
e
172+
))),
173+
}
174+
});
153175

154-
// app.command("llm_coding_status", |payload| {
155-
// let session_id = get_str(&payload, "session_id").unwrap_or_default();
156-
// result_to_json(llm_coding::session_status(session_id))
157-
// });
176+
app.command("llm_coding_freeze", |payload| {
177+
let session_id = get_str(&payload, "session_id").unwrap_or_default();
178+
result_str_to_json(llm_coding::commands::llm_coding_freeze(session_id))
179+
});
158180

159-
// app.command("llm_coding_list", |_payload| {
160-
// result_to_json(llm_coding::list_sessions())
161-
// });
181+
app.command("llm_coding_thaw", |payload| {
182+
let session_id = get_str(&payload, "session_id").unwrap_or_default();
183+
result_str_to_json(llm_coding::commands::llm_coding_thaw(session_id))
184+
});
162185

163-
// -----------------------------------------------------------------------
164-
// Groove commands
165-
// -----------------------------------------------------------------------
186+
app.command("llm_coding_terminate", |payload| {
187+
let session_id = get_str(&payload, "session_id").unwrap_or_default();
188+
result_str_to_json(llm_coding::commands::llm_coding_terminate(session_id))
189+
});
166190

167-
// app.command("groove_discover", |_payload| {
168-
// result_to_json(groove::discover())
169-
// });
191+
app.command("llm_coding_list_sessions", |_payload| {
192+
result_str_to_json(llm_coding::commands::llm_coding_list_sessions())
193+
});
170194

171-
// app.command("groove_status", |_payload| {
172-
// result_to_json(groove::status())
173-
// });
195+
app.command("llm_coding_session_status", |payload| {
196+
let session_id = get_str(&payload, "session_id").unwrap_or_default();
197+
result_str_to_json(llm_coding::commands::llm_coding_session_status(session_id))
198+
});
199+
200+
app.command("llm_coding_append_message", |payload| {
201+
let session_id = get_str(&payload, "session_id").unwrap_or_default();
202+
let content = get_str(&payload, "content").unwrap_or_default();
203+
result_str_to_json(llm_coding::commands::llm_coding_append_message(
204+
session_id, content,
205+
))
206+
});
207+
208+
app.command("llm_coding_get_messages", |payload| {
209+
let session_id = get_str(&payload, "session_id").unwrap_or_default();
210+
result_str_to_json(llm_coding::commands::llm_coding_get_messages(session_id))
211+
});
212+
213+
// -----------------------------------------------------------------------
214+
// Groove discovery — no commands.
215+
//
216+
// Groove is an external discovery surface: peers probe
217+
// `GET /.well-known/groove` on port 8000 to find PanLL's panel-ui
218+
// capability. The server is launched in `main()` via `groove::spawn()`,
219+
// which also starts the mesh monitor. There is nothing for the webview
220+
// to call locally.
221+
// -----------------------------------------------------------------------
174222

175223
// -----------------------------------------------------------------------
176224
// Service Registry commands (Connected Workbench v0.2.0)

0 commit comments

Comments
 (0)