Add render tab to tree editor, switch MCP paths to SX format

Tree editor island now has 4 tabs: tree, context, validate, render.
The render tab evaluates SX source as live HTML — type a (div (h2 "Hello"))
and see it rendered immediately.

MCP server paths changed from JSON arrays [0,2,1] to SX strings "(0 2 1)".
Fixes serialization issues and is more natural for an SX tool. The
json_to_path function now parses SX via sx-parse.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 20:35:40 +00:00
parent 6d0e512f19
commit 63babc0d2d
2 changed files with 14 additions and 194 deletions

View File

@@ -174,9 +174,20 @@ let parse_file path =
let exprs = Sx_parser.parse_all src in
List exprs
let parse_path_str s =
(* Parse SX path string: "(0 3 2)" or "0 3 2" → SX list of numbers *)
let exprs = Sx_parser.parse_all s in
match exprs with
| [List items] ->
(* (0 3 2) → list of numbers *)
List (List.map (fun x -> match x with Number _ -> x | _ -> Number 0.0) items)
| _ ->
(* Bare numbers: "0 3 2" → parsed as separate exprs *)
List (List.map (fun x -> match x with Number _ -> x | _ -> Number 0.0) exprs)
let json_to_path j =
let open Yojson.Safe.Util in
List (List.map (fun x -> Number (float_of_int (to_int x))) (to_list j))
parse_path_str (to_string j)
let value_to_string v =
match v with
@@ -311,7 +322,7 @@ let tool name desc props required =
("properties", `Assoc props)])]
let file_prop = ("file", `Assoc [("type", `String "string"); ("description", `String "Path to .sx file")])
let path_prop = ("path", `Assoc [("type", `String "array"); ("items", `Assoc [("type", `String "integer")]); ("description", `String "Index path, e.g. [0,2,1]")])
let path_prop = ("path", `Assoc [("type", `String "string"); ("description", `String "SX path, e.g. \"(0 2 1)\"")])
let tool_definitions = `List [
tool "sx_read_tree" "Read an .sx file as an annotated tree with path labels on every node. Use this to understand structure before editing."

File diff suppressed because one or more lines are too long