(** Neovere Live - Interactive Urbit runtime with Eio *) open Eio.Std open Nock_lib let version = "0.1.0" let project_root = match Sys.getenv_opt "NEOVERE_ROOT" with | Some root -> root | None -> let exe_dir = Filename.dirname Sys.executable_name in let rec find_root dir = let pills_dir = Filename.concat dir "pills" in if Sys.file_exists pills_dir && Sys.is_directory pills_dir then dir else let parent = Filename.dirname dir in if String.equal parent dir then failwith "unable to locate project root containing pills/" else find_root parent in find_root exe_dir (** Boot the ship *) let boot_ship pier_name = traceln "Booting ship: %s" pier_name; let pier_path = Filename.concat project_root pier_name in if Sys.file_exists pier_path then begin traceln "Error: Pier %s already exists" pier_path; exit 1 end; Unix.mkdir pier_path 0o755; let state = State.create ~pier_path () in (* Boot ivory *) let ivory_path = Filename.concat project_root "pills/ivory.pill" in begin match Boot.boot_ivory state ivory_path with | Error _ -> traceln "Ivory boot failed"; exit 1 | Ok () -> traceln "✓ Ivory kernel loaded" end; (* Boot solid *) let solid_path = Filename.concat project_root "pills/solid.pill" in begin match Boot.boot_solid_lifecycle state solid_path with | Error _ -> traceln "Solid boot failed"; exit 1 | Ok () -> traceln "✓ Solid boot complete (events: %Ld)" (State.event_number state) end; state (** Main event loop using Eio's structured concurrency *) let run_event_loop env state = let stdin = Eio.Stdenv.stdin env in let stdout = Eio.Stdenv.stdout env in let clock = Eio.Stdenv.clock env in traceln "\n~zod:dojo> "; Eio.Flow.copy_string "~zod:dojo> " stdout; (* Create Dill wire for terminal 1 *) let dill_wire = Noun.cell (Noun.atom (Z.of_int (Char.code 'd'))) (Noun.cell (Noun.atom_of_string "term") (Noun.cell (Noun.atom (Z.of_int 1)) (Noun.atom Z.zero))) in (* Process effects helper *) let process_effects result = match result with | Noun.Cell (effects, _new_core) -> Nock_lib.Dill.render_effects ~stdout effects | _ -> traceln "Warning: poke returned unexpected structure" in (* Run concurrent fibers *) Switch.run @@ fun _sw -> Fiber.all [ (* Terminal input fiber *) (fun () -> traceln "[Input fiber started]"; Nock_lib.Dill.input_loop ~stdin ~state ~wire:dill_wire process_effects ); (* Timer fiber (placeholder) *) (fun () -> traceln "[Timer fiber started]"; while true do Eio.Time.sleep clock 10.0; traceln "[Timer tick]" done ); (* Status fiber (placeholder) *) (fun () -> traceln "[Status fiber started]"; Eio.Time.sleep clock 5.0; let eve = State.event_number state in traceln "[Status] Events: %Ld" eve; ); ] (** Main entry point *) let main env = let pier_name = if Array.length Sys.argv > 1 then Sys.argv.(1) else "zod-live" in traceln "╔═══════════════════════════════════════════════════════╗"; traceln "║ Neovere Live v%s ║" version; traceln "╚═══════════════════════════════════════════════════════╝"; traceln ""; (* Boot ship *) let state = boot_ship pier_name in traceln ""; traceln "Ship booted successfully!"; traceln "Starting event loop with Eio structured concurrency..."; traceln ""; (* Run event loop *) run_event_loop env state; (* Cleanup *) State.close_eventlog state; traceln "Shutdown complete" let () = Eio_main.run @@ fun env -> try main env with | Sys_error msg -> traceln "System error: %s" msg; exit 1 | e -> traceln "Fatal error: %s" (Printexc.to_string e); Printexc.print_backtrace stderr; exit 1