#!/usr/bin/env python3 """Output JS build manifest as structured text for the MCP server.""" from __future__ import annotations import json import os import re import sys _HERE = os.path.dirname(os.path.abspath(__file__)) _PROJECT = os.path.abspath(os.path.join(_HERE, "..", "..")) if _PROJECT not in sys.path: sys.path.insert(0, _PROJECT) from hosts.javascript.platform import ( ADAPTER_FILES, ADAPTER_DEPS, SPEC_MODULES, SPEC_MODULE_ORDER, PRIMITIVES_JS_MODULES, _ALL_JS_MODULES, EXTENSION_NAMES, ) def extract_primitives(js_code: str) -> list[str]: """Extract PRIMITIVES["name"] registrations from JS code.""" return sorted(set(re.findall(r'PRIMITIVES\["([^"]+)"\]', js_code))) def main(): # Core spec files (always included) core_files = [ "evaluator.sx (frames + eval + CEK)", "freeze.sx (serializable state)", "content.sx (content-addressed computation)", "render.sx (core renderer)", "web-forms.sx (defstyle, deftype, defeffect)", ] # Adapters adapter_lines = [] for name, (filename, label) in sorted(ADAPTER_FILES.items()): deps = ADAPTER_DEPS.get(name, []) dep_str = f" (deps: {', '.join(deps)})" if deps else "" adapter_lines.append(f" {name:18s} {filename:22s} {label}{dep_str}") # Spec modules module_lines = [] for name in SPEC_MODULE_ORDER: if name in SPEC_MODULES: filename, label = SPEC_MODULES[name] module_lines.append(f" {name:18s} {filename:22s} {label}") # Extensions ext_lines = [f" {name}" for name in sorted(EXTENSION_NAMES)] # Primitive modules prim_lines = [] for mod_name in sorted(_ALL_JS_MODULES): if mod_name in PRIMITIVES_JS_MODULES: prims = extract_primitives(PRIMITIVES_JS_MODULES[mod_name]) prim_lines.append(f" {mod_name} ({len(prims)}): {', '.join(prims)}") # Current build file build_path = os.path.join(_PROJECT, "shared", "static", "scripts", "sx-browser.js") build_info = "" if os.path.exists(build_path): size = os.path.getsize(build_path) mtime = os.path.getmtime(build_path) from datetime import datetime ts = datetime.fromtimestamp(mtime).strftime("%Y-%m-%d %H:%M:%S") # Count PRIMITIVES in actual build with open(build_path) as f: content = f.read() actual_prims = extract_primitives(content) build_info = f"\nCurrent build: {size:,} bytes, {ts}, {len(actual_prims)} primitives registered" print(f"""JS Build Manifest ================= {build_info} Core files (always included): {chr(10).join(' ' + f for f in core_files)} Adapters ({len(ADAPTER_FILES)}): {chr(10).join(adapter_lines)} Spec modules ({len(SPEC_MODULES)}, order: {' → '.join(SPEC_MODULE_ORDER)}): {chr(10).join(module_lines)} Extensions ({len(EXTENSION_NAMES)}): {chr(10).join(ext_lines)} Primitive modules ({len(_ALL_JS_MODULES)}): {chr(10).join(prim_lines)}""") if __name__ == "__main__": main()