summaryrefslogtreecommitdiff
path: root/ocaml/bin/neovere.ml
diff options
context:
space:
mode:
Diffstat (limited to 'ocaml/bin/neovere.ml')
-rw-r--r--ocaml/bin/neovere.ml190
1 files changed, 190 insertions, 0 deletions
diff --git a/ocaml/bin/neovere.ml b/ocaml/bin/neovere.ml
new file mode 100644
index 0000000..0d40ce0
--- /dev/null
+++ b/ocaml/bin/neovere.ml
@@ -0,0 +1,190 @@
+(** Neovere - OCaml Urbit Runtime
+ *
+ * Boot a new ship with Urbit-style boot screen
+ *)
+
+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
+
+(* Ship name helper *)
+let ship_name = "zod"
+let ship_sigil = "~zod"
+
+(* Urbit-style boot messages *)
+let print_header () =
+ Printf.printf "urbit %s\n" version;
+ Printf.printf "boot: home is %s\n" ship_name;
+ Printf.printf "loom: mapped 2048MB\n";
+ Printf.printf "%!"
+
+let print_boot_start pill_path =
+ Printf.printf "boot: loading pill %s\n%!" pill_path
+
+let print_pill_info bot_count mod_count use_count =
+ let total = bot_count + mod_count + use_count in
+ Printf.printf "boot: %%solid pill\n";
+ Printf.printf "boot: protected loom\n";
+ Printf.printf "live: logical boot\n";
+ Printf.printf "boot: installed 0 jets\n";
+ Printf.printf "---------------- playback starting ----------------\n";
+ Printf.printf "pier: replaying events 1-%d\n%!" total
+
+let print_lifecycle_start () =
+ Printf.printf "arvo: metamorphosis\n%!"
+
+let print_playback_done event_count =
+ Printf.printf "pier: (%d): play: done\n" event_count;
+ Printf.printf "---------------- playback complete ----------------\n%!"
+
+let print_network_info () =
+ Printf.printf "ames: live on 0 (localhost only)\n";
+ Printf.printf "http: web interface live on http://localhost:8080\n";
+ Printf.printf "http: loopback live on http://localhost:12321\n%!"
+
+let print_ready event_count =
+ Printf.printf "pier (%d): live\n" event_count;
+ Printf.printf "%s:dojo> %!" ship_sigil
+
+(* Count events in noun list *)
+let rec count_noun_list = function
+ | Noun.Atom z when Z.equal z Z.zero -> 0
+ | Noun.Cell (_, t) -> 1 + count_noun_list t
+ | _ -> 0
+
+(* Boot from pill *)
+let boot_ship pier_name =
+ print_header ();
+
+ (* Create pier directory *)
+ let pier_path = Filename.concat project_root pier_name in
+ if Sys.file_exists pier_path then begin
+ Printf.eprintf "Error: Pier directory %s already exists\n" pier_path;
+ Printf.eprintf "Hint: Remove it first (rm -rf %s)\n" pier_path;
+ exit 1
+ end;
+
+ Unix.mkdir pier_path 0o755;
+
+ (* Boot from pills *)
+ let ivory_path = Filename.concat project_root "pills/ivory.pill" in
+ let solid_path = Filename.concat project_root "pills/solid.pill" in
+
+ (* Create state *)
+ let state = State.create ~pier_path () in
+
+ (* Load ivory first (silently) *)
+ let () = match Boot.boot_ivory state ivory_path with
+ | Error (Boot.Invalid_pill msg) ->
+ Printf.eprintf "✗ Ivory boot failed: %s\n" msg;
+ exit 1
+ | Error (Boot.Unsupported msg) ->
+ Printf.eprintf "✗ Unsupported: %s\n" msg;
+ exit 1
+ | Ok () -> ()
+ in
+
+ (* Now load solid with progress *)
+ print_boot_start solid_path;
+
+ (* Parse pill to get event counts *)
+ let pill = Boot.cue_file solid_path in
+ let (bot, mod_, use_) = match Boot.parse_solid pill with
+ | Error _ ->
+ Printf.eprintf "Error: Failed to parse solid pill\n";
+ exit 1
+ | Ok result -> result
+ in
+
+ let bot_count = count_noun_list bot in
+ let mod_count = count_noun_list mod_ in
+ let use_count = count_noun_list use_ in
+
+ (* Add the 4 system events and 1 boot event we'll inject *)
+ print_pill_info bot_count (mod_count + 4) (use_count + 1);
+
+ (* Run lifecycle boot *)
+ print_lifecycle_start ();
+
+ let boot_start = Sys.time () in
+ let () = match Boot.boot_solid_lifecycle state solid_path with
+ | Error (Boot.Invalid_pill msg) ->
+ Printf.eprintf "✗ Boot failed: %s\n" msg;
+ exit 1
+ | Error (Boot.Unsupported msg) ->
+ Printf.eprintf "✗ Unsupported: %s\n" msg;
+ exit 1
+ | Ok () -> ()
+ in
+ let boot_elapsed = Sys.time () -. boot_start in
+
+ Printf.printf "clay: kernel updated to solid\n";
+
+ let eve = State.event_number state in
+ print_playback_done (Int64.to_int eve);
+
+ (* Show boot time *)
+ Printf.printf "boot: complete in %.2fs\n" boot_elapsed;
+ Printf.printf "\n";
+
+ (* Network info *)
+ print_network_info ();
+
+ (* Ready! *)
+ print_ready (Int64.to_int eve);
+
+ (* Close eventlog *)
+ State.close_eventlog state;
+
+ (* Show status *)
+ Printf.printf "\n\n";
+ Printf.printf "╔═══════════════════════════════════════════════════════╗\n";
+ Printf.printf "║ Neovere Boot Complete! 🎉 ║\n";
+ Printf.printf "╚═══════════════════════════════════════════════════════╝\n";
+ Printf.printf "\n";
+ Printf.printf "Pier: %s\n" pier_path;
+ Printf.printf "Events: %Ld\n" eve;
+ Printf.printf "Kernel: %s\n" (if Noun.is_cell (State.arvo_core state) then "valid" else "invalid");
+ Printf.printf "\n";
+ Printf.printf "Next steps:\n";
+ Printf.printf " - Event loop and I/O drivers (Dill, Ames, Eyre)\n";
+ Printf.printf " - Effects processing\n";
+ Printf.printf " - Interactive dojo\n";
+ Printf.printf "\n"
+
+(* Main *)
+let () =
+ let pier_name =
+ if Array.length Sys.argv > 1 then Sys.argv.(1)
+ else "zod"
+ in
+
+ try
+ boot_ship pier_name
+ with
+ | Sys_error msg ->
+ Printf.eprintf "\nSystem error: %s\n" msg;
+ exit 1
+ | Failure msg ->
+ Printf.eprintf "\nError: %s\n" msg;
+ exit 1
+ | e ->
+ Printf.eprintf "\nFatal error: %s\n" (Printexc.to_string e);
+ Printexc.print_backtrace stderr;
+ exit 1