@@ -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+
8294fn 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
125137fn 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