Fix WASM browser click handlers: 8 bugs, 50 new VM tests
The sx-get links were doing full page refreshes because click handlers never attached. Root causes: VM frame management bug, missing primitives, CEK/VM type dispatch mismatch, and silent error swallowing. Fixes: - VM frame exhaustion: frames <- [] now properly pops to rest_frames - length primitive: add alias for len in OCaml primitives - call_sx_fn: use sx_call directly instead of eval_expr (CEK checks for type "lambda" but VmClosure reports "function") - Boot error surfacing: Sx.init() now has try/catch + failure summary - Callback error surfacing: catch-all handler for non-Eval_error exceptions - Silent JIT failures: log before CEK fallback instead of swallowing - vm→env sync: loadModule now calls sync_vm_to_env() - sx_build_bytecode MCP tool added for bytecode compilation Tests: 50 new tests across test-vm.sx and test-vm-primitives.sx covering nested VM calls, frame integrity, CEK bridge, primitive availability, cross-module symbol resolution, and callback dispatch. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -519,6 +519,21 @@ let rec handle_tool name args =
|
||||
| Unix.WEXITED 0 -> text_result (Printf.sprintf "OK — %s build succeeded\n%s" target (String.trim output))
|
||||
| _ -> error_result (Printf.sprintf "%s build failed:\n%s" target output))
|
||||
|
||||
| "sx_build_bytecode" ->
|
||||
let project_dir = try Sys.getenv "SX_PROJECT_DIR" with Not_found ->
|
||||
let spec_dir = try Sys.getenv "SX_SPEC_DIR" with Not_found -> "spec" in
|
||||
Filename.dirname spec_dir
|
||||
in
|
||||
let cmd = Printf.sprintf "cd %s && node hosts/ocaml/browser/compile-modules.js shared/static/wasm 2>&1" project_dir in
|
||||
let ic = Unix.open_process_in cmd in
|
||||
let lines = ref [] in
|
||||
(try while true do lines := input_line ic :: !lines done with End_of_file -> ());
|
||||
let status = Unix.close_process_in ic in
|
||||
let output = String.concat "\n" (List.rev !lines) in
|
||||
(match status with
|
||||
| Unix.WEXITED 0 -> text_result (Printf.sprintf "OK — bytecode compilation succeeded\n%s" (String.trim output))
|
||||
| _ -> error_result (Printf.sprintf "Bytecode compilation failed:\n%s" output))
|
||||
|
||||
| "sx_test" ->
|
||||
let host = args |> member "host" |> to_string_option |> Option.value ~default:"js" in
|
||||
let full = args |> member "full" |> to_bool_option |> Option.value ~default:false in
|
||||
@@ -748,8 +763,10 @@ let rec handle_tool name args =
|
||||
(match actions with Some a -> Some ("actions", `String a) | None -> None);
|
||||
(match island with Some i -> Some ("island", `String i) | None -> None);
|
||||
]) in
|
||||
let args_json = Yojson.Safe.to_string (Yojson.Safe.from_string (Yojson.Basic.to_string inspector_args)) in
|
||||
let cmd = Printf.sprintf "cd %s && node tests/playwright/sx-inspect.js '%s' 2>&1" project_dir (String.escaped args_json) in
|
||||
let args_json = Yojson.Basic.to_string inspector_args in
|
||||
(* Single-quote shell wrapping — escape any literal single quotes in JSON *)
|
||||
let shell_safe = String.concat "'\\''" (String.split_on_char '\'' args_json) in
|
||||
let cmd = Printf.sprintf "cd %s && node tests/playwright/sx-inspect.js '%s' 2>&1" project_dir shell_safe in
|
||||
let ic = Unix.open_process_in cmd in
|
||||
let lines = ref [] in
|
||||
(try while true do lines := input_line ic :: !lines done with End_of_file -> ());
|
||||
@@ -1304,6 +1321,8 @@ let tool_definitions = `List [
|
||||
[("target", `Assoc [("type", `String "string"); ("description", `String "Build target: \"js\" (default) or \"ocaml\"")]);
|
||||
("full", `Assoc [("type", `String "boolean"); ("description", `String "Include extensions and type system (default: false)")])]
|
||||
[];
|
||||
tool "sx_build_bytecode" "Compile all web .sx files to pre-compiled .sxbc.json bytecode modules for the WASM browser kernel."
|
||||
[] [];
|
||||
tool "sx_test" "Run SX test suite. Returns pass/fail summary and any failures."
|
||||
[("host", `Assoc [("type", `String "string"); ("description", `String "Test host: \"js\" (default) or \"ocaml\"")]);
|
||||
("full", `Assoc [("type", `String "boolean"); ("description", `String "Run full test suite including extensions (default: false)")])]
|
||||
@@ -1354,13 +1373,13 @@ let tool_definitions = `List [
|
||||
("files", `Assoc [("type", `String "array"); ("items", `Assoc [("type", `String "string")]); ("description", `String "Multiple .sx files to load in order")]);
|
||||
("setup", `Assoc [("type", `String "string"); ("description", `String "SX setup expression to run before main evaluation")])]
|
||||
["expr"];
|
||||
tool "sx_playwright" "Run Playwright browser tests or inspect SX pages interactively. Modes: run (spec files), inspect (page/island report with leak detection and handler audit), diff (full SSR vs hydrated DOM), hydrate (lake-focused SSR vs hydrated comparison — detects clobbering), eval (JS expression), interact (action sequence), screenshot."
|
||||
tool "sx_playwright" "Run Playwright browser tests or inspect SX pages interactively. Modes: run (spec files), inspect (page/island report with leak detection and handler audit), diff (full SSR vs hydrated DOM), hydrate (lake-focused SSR vs hydrated comparison — detects clobbering), eval (JS expression), interact (action sequence), screenshot, listeners (CDP event listener inspection), trace (click + capture console/network/pushState), cdp (raw CDP command)."
|
||||
[("spec", `Assoc [("type", `String "string"); ("description", `String "Spec file to run (run mode). e.g. stepper.spec.js")]);
|
||||
("mode", `Assoc [("type", `String "string"); ("description", `String "Mode: run, inspect, diff, hydrate, eval, interact, screenshot")]);
|
||||
("mode", `Assoc [("type", `String "string"); ("description", `String "Mode: run, inspect, diff, hydrate, eval, interact, screenshot, listeners, trace, cdp")]);
|
||||
("url", `Assoc [("type", `String "string"); ("description", `String "URL path to navigate to (default: /)")]);
|
||||
("island", `Assoc [("type", `String "string"); ("description", `String "Filter inspect to a specific island by name (e.g. home/stepper)")]);
|
||||
("selector", `Assoc [("type", `String "string"); ("description", `String "CSS selector to focus on (screenshot mode)")]);
|
||||
("expr", `Assoc [("type", `String "string"); ("description", `String "JS expression to evaluate (eval mode)")]);
|
||||
("selector", `Assoc [("type", `String "string"); ("description", `String "CSS selector for screenshot/listeners/trace modes")]);
|
||||
("expr", `Assoc [("type", `String "string"); ("description", `String "JS expression (eval mode), selector (listeners/trace), or CDP command (cdp mode)")]);
|
||||
("actions", `Assoc [("type", `String "string"); ("description", `String "Semicolon-separated action sequence (interact mode). Actions: click:sel, fill:sel:val, wait:ms, text:sel, html:sel, attrs:sel, screenshot, screenshot:sel, count:sel, visible:sel")])]
|
||||
[];
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user