commits
New blog posts (monopam-madness, open-source-and-ai, weeknotes-2026-10),
notebook showcase with card layout and screenshots, Atom feed generator,
foundations notebook fixes, ONNX test improvements, widget interaction
tests, deploy script updates for oxcaml switch, and .gitignore for
build artifacts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The oxcaml compiler changed cmi_crcs from (string * Digest.t option) list
to Import_info.t array, and Env.crc_of_unit now takes Compilation_unit.Name.t
instead of string. Update all three call sites accordingly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Commands sent before Leaflet finishes loading were silently dropped.
Now they are queued and replayed once the map initializes. This fixes
enableBboxDraw being lost when called immediately after display_managed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests addMarker, clearMarkers, addImageOverlay, removeImageOverlay
commands in a standalone HTML page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New commands:
- enableBboxDraw: custom rectangle drawing with bbox_drawn event
- addImageOverlay/removeImageOverlay: display data URL images on map
- addMarker/clearMarkers: circle markers with labels
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of requiring every .mld file to specify @x-ocaml.universe and
@x-ocaml.worker tags individually, configure the default universe path
once in dune-workspace (--config x-ocaml.universe=/_opam). The shell
emits <meta> tags from config values, and per-page @x-ocaml tags can
still override them.
Changes:
- dune-workspace: add --config x-ocaml.universe=/_opam to html_flags
- gen_rules.ml: pass --config to odoc html-generate for @site build
- odoc_jon_shell.ml: emit <meta> tags from x-ocaml.* config values
- odoc generator.ml: pass config to shell page_creator
- interactive_extension.ml: upsert meta tags (update existing or create)
- x_ocaml.ml: infer jtw backend from x-ocaml-universe meta tag
- Remove @x-ocaml.universe/@x-ocaml.worker from 14 .mld files using
the default /_opam universe
- deploy-site.sh: add dune install x-ocaml, chmod fix, widget-leaflet
- findlibish.ml: module detection fallback via jsoo runtime
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests the full end-to-end flow of runtime preloaded package detection:
- Preloaded package (yojson): succeeds without fetching .cma.js
- Normal package (stringext): fetches and loads from universe
- CRC mismatch (crc_conflict): raises Crc_mismatch with bogus CRC
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add symtable_memo and crc_memo hash tables to Impl for caching
module availability and CRC lookups (both binary and server side)
- Extract pure check_preload_status function into Impl for testability
- Capture server-side CRCs from fetched .cmi files in add_dynamic_cmis_sync
- Raise Crc_mismatch exception (instead of returning false) when a
preloaded package has different CRCs than the universe
- Add 8 ppx_expect tests covering: match, mismatch, partial load,
empty, missing CRCs, server CRC priority, single mismatch in group
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bake module CRCs into dynamic_cmis.json when building universes, then
verify at require-time that preloaded modules match the universe version.
Three defensive checks:
- All modules loaded: package is preloaded (skip import)
- No modules loaded: package is not preloaded (import normally)
- Partial: warn and import (something is wrong)
- CRC mismatch: warn and import (version skew between binary and universe)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use relativize_or_fallback for META files (already used for CMI files),
fixing a None exception when libraries are installed outside the
standard findlib tree.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use Symtable.Global.of_ident / is_global_defined to detect packages
already linked into the worker binary at runtime, eliminating the
hand-maintained list that drifts out of sync with example/dune deps.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove bisect_ppx from odoc (opam dep + 11 instrumentation stanzas)
- Remove unix and findlib from js_top_worker-unix.opam (not opam packages)
- Remove bisect_ppx, findlib, unix from root dune-project
- Add mdx with :with-test guard
- Delete experiments/widget-bridge (stale, removed lwd/note deps)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add index.mld files for all packages that were missing them, which
caused odoc to generate default pages titled "<package> index". Also
fix leaf item indentation by always adding a spacer span regardless
of the node kind.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ppxlib (~5.5MB of bytecode) was statically linked into every worker.js,
even though most users never use PPX rewriters. Replace the custom
JsooTopPpx module with the standard OCaml toplevel mechanism:
Ast_mapper.register + Toploop.preprocess_phrase. PPX packages are now
loaded on-demand via #require, with ppxlib_register bridging ppxlib
into the Ast_mapper pipeline.
Worker size: 67MB → 56MB (11MB / 16% reduction).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add cppo preprocessing for merlin-js and x-ocaml workers to support
conditional compilation with OXCAML flag
- Guard day10 packages with enabled_if >= 5.3.0 since they need recent OCaml
- Remove fatal odoc warnings from dune-workspace (handled per-package now)
- Bump merlin-js dune lang to 3.17
- Add warning suppression flags where needed (-w -58, -w -67)
- Add interactive extension exercise pages (FOCS 2020/2024/2025, OxCaml
stack allocation)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add managed widget protocol (display_managed, command, register_adapter)
for external widget adapters like Leaflet maps
- Extract Leaflet map adapter into separate js_top_worker-widget-leaflet
library, loadable via #require
- Add widget rendering to x-ocaml web component (widget_render.ml) so
widgets work in .mld documentation pages
- Wire widget callbacks through OCaml client (js_top_worker_client_msg.ml)
- Complete the preloaded list in findlibish.ml to match all transitive
worker dependencies, preventing "file already exists" errors when
#require loads packages already compiled into the worker
- Add demo_widgets.mld and demo_map.mld documentation pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Widget.View re-export of Widget_view for toplevel access
- Copy ocaml-worker.js to build output via dune rule
- Use worker.bc.js for local dev testing
- Update test code to use Widget.View instead of Widget_view
- Add diagnostic eval and error logging to test page
All four widget tests now pass in browser: static widget,
interactive counter, slider, and cross-cell signal propagation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add js_top_worker-widget and note to the example worker's dependencies,
and create widget_test.html with three interactive test cases: a static
widget, an FRP counter with increment/decrement buttons, and a slider
with a cross-cell derived display.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Initialize Widget.set_sender at worker startup so widget view updates
are sent via Worker.post_message. Handle incoming WidgetEvent messages
by routing them through Widget.handle_event. Add WidgetUpdate/WidgetClear
catch-all cases in the OCaml client to suppress non-exhaustive match
warnings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add widget_update and widget_clear message handling to _handleMessage,
onWidgetUpdate/onWidgetClear callbacks to constructor options, and
sendWidgetEvent method for sending widget events to the worker.
Update TypeScript declarations with corresponding interfaces and types.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix sidebar kindBadge: map leaf-page→pg, module-type→MT, etc. (was
showing "L" for leaf-page entries)
- Stop escaping sidebar content HTML (entries contain <code> tags)
- Fix inline sidebar JSON: use Html.cdata_script instead of Html.txt
to prevent HTML-escaping inside <script> tags
- Add --xo-* CSS custom properties for x-ocaml cells in light/dark themes
- Fix support file registration: use 'opam var share' instead of
'opam var x-ocaml:share' (works without x-ocaml being an opam package)
- Suppress empty <li> from config-only extension tags (@x-ocaml.*)
- Add worker_url field to jtw opam findlib_index.json
- Refactor x-ocaml.js worker URL discovery to support both direct
worker_url and day10-style version/content_hash paths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove 12 JS stubs from js_top_worker that are already provided by
basement/runtime.js and base/runtime.js (blocking_mutex, blocking_condition,
thread_yield, basement_dynamic, basement_alloc_stack_bind, caml_ml_domain_index)
- Keep caml_make_local_vect as it's needed by OxCaml compiler-libs and base
is not a transitive dependency
- Fix free-variables warnings by using proper //Provides/Requires pattern
for domain TLS shared state
- Add (link_flags (-linkall)) to odoc-scrollycode-extension test binary so
Html_page's side-effect shell registration is linked (matches real odoc binary)
- Promote test expected outputs for OCaml 5.4.1 and scrollycode extension changes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- findlibish.mli: use Js_top_worker.Impl.dynamic_cmis (RPC module removed)
- worker.ml: use Impl.dcs_url instead of Toplevel_api_gen.dcs_url
- x-ocaml/src/jtw_client: convert to cppo for OxCaml-only
ppx_template_generated field in Query_protocol.Compl
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Consolidate js_top_worker and odoc dual-compiler stanzas into single
library stanzas with cppo rules generating impl.ml from impl.cppo.ml
- Per-package findlib_index.json with relative universe paths (../dep)
and implicit stdlib dependency injection
- Add find_stdlib_dcs to Impl.S interface for stdlib CMI lookup via
findlib metadata instead of hardcoded URLs
- Replace jsoo Json.output/Json.unsafe_input with plain JSON.stringify/
JSON.parse for cross-jsoo-version compatibility (6.0.1+ox vs 6.2.0)
- Cross-origin worker support: set __global_rel_url in blob worker,
skip URL rewriting for absolute http(s) URLs
- Fix odoc doc comments and ocamlformat-ignore for cppo files
- Add demo docs, helper scripts, and x-ocaml package-lock.json
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The core META file defines jsoo_runtime with newline-separated filenames,
but the parser only split on spaces. This left trailing newlines embedded
in file paths, causing js_of_ocaml to fail when compiling core.cma.js.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The project migrated from rpclib/ppx_deriving_rpc JSON-RPC to a simple
message-passing protocol but the old RPC infrastructure remained wired
in. This removes it entirely (~5400 lines deleted):
- Move API types from Toplevel_api_gen into Impl, replace Rpc_lwt.ErrM
with plain Lwt + result
- Replace Jsonrpc/Rpcmarshal JSON serialization with Yojson.Safe
- Rewrite all tests to call Impl.Make(S) directly instead of via RPC
server/client roundtrip
- Rewrite examples and browser tests to use message protocol client
- Delete RPC source files, _old/ directory, and dead opam packages
- Remove rpclib dependencies from all dune and opam files
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable loading .cma.js files from a different origin (e.g., ocaml.org)
by working around Chrome's CORB which blocks cross-origin importScripts
for files with embedded binary CMI data.
worker.ml: detect cross-origin URLs in import_scripts and use
synchronous XHR + eval() instead of importScripts. Same-origin
URLs continue to use the standard path.
jtw_client.ml: create blob: URL wrapper for cross-origin worker.js
(browsers block cross-origin Worker construction), derive stdlib_dcs
URL from findlib_index base, switch to eval_stream for streaming
phrase-by-phrase output.
interactive_extension.ml: always load x-ocaml.js and worker.js from
local _x-ocaml/ path (same-origin), communicate universe URL via
<meta> tag. Set backend to "jtw" when a universe is configured.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- findlibish: if fetching findlib_index.json fails, retry without the
.json extension for backward compatibility with older universes
- Update design doc status table: odoc-interactive-extension and
universe builder are now implemented
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add --copy-file flag to jtw opam/opam-all for including x-ocaml.js
and other assets in universe output
- Pass findlib_requires and findlib_index from meta tags through to
the JTW worker init, so @x-ocaml.requires packages are loaded
during setup
- x_ocaml.ml reads <meta name="x-ocaml-packages"> and
<meta name="x-ocaml-universe"> before creating the backend
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add optional ?filename parameter to complete, type_at, and errors
functions. When provided, filename is included in the JSON message
sent to the worker.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add optional filename parameter to Complete, TypeAt, and Errors
messages so Merlin can be configured for .mli vs .ml files.
Thread filename through impl.ml's config/wdispatch/query functions
and wire it in worker.ml's message handler.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Writers (jtw.ml opam mode, jtw_gen.ml day10 mode): output filename
changed from findlib_index to findlib_index.json, JSON key from
"metas" to "meta_files".
Reader (findlibish.ml): universe link resolution uses .json extension.
Runtime default (impl.ml): changed from "findlib_index" to
"findlib_index.json".
JS client, test fixtures, HTML test pages, and documentation updated
to match.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Bump root dune-project to (lang dune 3.21) for odoc v3 rules
- Remove (package odoc) from odoc_model_semantics_test library
- Remove (package js_top_worker_rpc_def) to work around directory-targets
bug in dune's doc generation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Escape curly braces and fix odoc reference syntax to eliminate warnings
with (warnings fatal):
- Replace {dir}, {pkg}, {hash} etc with [dir], [<pkg>], [<hash>] or
{[ code blocks ]} as appropriate
- Fix {!Stdlib.Out_channel.with_open_gen} -> [Out_channel.with_open_gen]
in sherlodoc type_polarity.mli
- Fix @scrolly.<theme> -> [@scrolly.<theme>] in scrollycode extension
- Fix JSON format in findlibish.ml doc comment
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The file was empty (0 bytes), making it an invalid opam package.
Added dependencies based on the dune build files that reference
this package.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add comprehensive JS stubs for OxCaml-specific primitives (domain TLS,
arch detection, blocking sync, basement/capsule) needed by the OxCaml
js_of_ocaml runtime
- Fix demo.js to load rpc_worker.bc.js (JSON-RPC) instead of the
non-RPC _opam/worker.js, fixing a protocol mismatch bug
- Fix exec RPC method never resolving: rename phrase_p parameter from
~name:"string" to unnamed, preventing rpclib from incorrectly treating
the phrase as a named parameter in the dispatch dict
- Remove unused cbort, zarith, bytesrw dependencies from opam and
dune-project
- Bump dune version in x-ocaml opam files to 3.21 for OxCaml support
- Update cram test expected output for current package list
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add support for building js_top_worker and odoc with both the standard
OCaml 5.4 compiler and the OxCaml 5.2.0+ox compiler using cppo
conditional compilation and dual dune stanzas.
js_top_worker changes:
- Bump dune-project to 3.21 for %{ocaml-config:ox} support
- Add dual library stanzas gated by (enabled_if %{ocaml-config:ox})
- Add cppo guards for OxCaml API differences:
- Compilation_unit.Name.t vs string for persistent loader
- Env.report_error ~level:0 (extra parameter)
- Language_extension.set_universe_and_enable_all (oxcaml-only)
- Unit_info.make ~for_pack_prefix (extra parameter)
- Typemod.type_implementation (extra Compilation_unit arg)
- Gate ppx_deriving_rpc with (not %{ocaml-config:ox})
odoc changes:
- Apply upstream oxcaml PR #1399 (art-w/upstream-oxcaml)
- Bump dune-project to 3.21
- Add dual stanzas in loader, model, xref2, odoc, syntax_highlighter
- Add cppo OXCAML guards for compiler API differences
- Support OxCaml features: modes, layouts, labeled tuples, iarray,
unboxed records, module type strengthening, polymorphic arguments,
call position arguments, Import_info.t, Compilation_unit.t
Verified end-to-end: scrollycode demos generate HTML and the
interactive playground evaluates OCaml code in the browser with
both compiler switches.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix client.ml absolute_url to handle root-relative paths (/ prefix)
using window.location.origin instead of page directory path
- Abstract merlin_ext.ml to use a post function closure instead of
concrete Client.t, decoupling from specific backend
- Update cell.ml/mli to accept eval/fmt/post function closures
instead of Client.t, and split init/start to avoid synchronous
response race condition with jtw backend
- Wire x_ocaml.ml to read backend attribute and dispatch through
Backend module (jtw or builtin)
- Add W.setup call after W.init in jtw_client to load stdlib
- Create rpc_worker.ml: full-featured JSON-RPC worker combining
the complete S module (findlibish, stdlib) with JSON-RPC protocol
Verified: code execution and Merlin type-on-hover both work in the
scrollycode playground overlay (hovering shows type tooltips like
"type bool = false | true").
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch OcamlWorker from fromManifest() to fromIndex(), which reads
compiler version and content_hash directly from the per-universe
findlib_index. This removes the dependency on a global manifest.json
and naturally supports multiple OCaml versions.
Update all HTML test pages and runner to use the new API, refresh
universe hashes to match content-addressed output, and expand
tutorial test definitions and Playwright specs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests per-solution OCaml version support: containers.3.14 requires
ocaml < 5.4 and is solved with 5.3.0, verifying the worker loads the
correct compiler and stdlib without inconsistent assumptions errors.
Also updates universe hashes to match content-addressed output.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add OcamlWorker.fromManifest() to discover content-hashed worker URLs
from manifest.json, and update all test pages to use it instead of
hardcoded compiler paths. This enables Cache-Control: immutable for
all artifact paths except manifest.json and findlib_index.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add browser-based integration tests and 30 interactive tutorials for
Daniel Bunzli's OCaml libraries, exercising the JTW (js_top_worker)
system with real opam packages compiled to JavaScript.
Tutorials cover Fmt, Cmdliner, Mtime, Logs, Uucp, Uunf, Astring,
Jsonm, Xmlm, Ptime, React, Hmap, Gg, Vg, Note, Otfm, Fpath, Uutf,
B0, and Bos across multiple versions, testing API evolution.
Also fixes incremental output accumulation in the client library and
adds setup documentation for reproducing the demo environment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ocamlfind, fpath, and js_of_ocaml-ppx are required by lib/dune
but were not declared.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ppx_deriving, ppxlib, merlin-lib, mime_printer, logs and cppo are
all required by lib/dune but were not declared in the opam file.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The message sub-library depends on js_of_ocaml and js_of_ocaml-ppx
but these were not declared in the opam file, causing build failures
when installed via opam pin.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace CBOR/channel-based transport with direct message passing.
Add OutputAt message type for incremental cell output streaming.
Remove unused channel.ml/mli and rpc_cbor.ml/mli modules.
Update client libraries with worker blob URL creation helper.
Add node-based incremental output test.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Browser tests:
- Add dune configuration for browser tests with Playwright
- Fix test_worker.ml to include js_of_ocaml-toplevel library
(required for toplevel initialization)
- Register all RPC methods in test worker
- Tests run via `dune build @runbrowser`
Cell dependency tests:
- Add node_dependency_test.ml with 26 tests covering:
- Linear dependencies (c1 → c2 → c3 → c4)
- Diamond dependencies (d1 → d2,d3 → d4)
- Missing dependency error handling
- Type update propagation
- Type shadowing across cells
- Complex module dependency graphs
- Key finding: dependencies are explicit, not transitive
Also adds docs/test-gaps-design.md documenting test coverage
gaps and implementation plan.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Restore comprehensive directives test (850+ lines) that was temporarily disabled
- Update expected outputs for current environment (OCaml 5.4.0)
Test infrastructure improvements:
- Socket path configurable via JS_TOP_WORKER_SOCK environment variable
- Worker forks: parent blocks until child is ready, then prints child PID and exits
- Child redirects stdout/stderr to /dev/null so shell $() capture completes
- No polling, no sleeps - deterministic pipe-based synchronization
- Each test uses unique socket path for parallel test isolation
Usage:
WORKER_PID=$(unix_worker) # Blocks until ready, returns child PID
unix_client init ... # Guaranteed to connect immediately
kill $WORKER_PID # Clean shutdown
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The expected output was captured in an invalid state and needs to be
regenerated. The simple.t test still runs and validates basic functionality.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
JavaScript client (client/ocaml-worker.js):
- ES module with async/await API for web applications
- TypeScript declarations (ocaml-worker.d.ts)
- Supports init, eval, complete, typeAt, errors, createEnv, destroyEnv
OCaml client (js_top_worker_client_msg):
- Uses new message protocol instead of RPC
- Lwt-based async API matching the JS client
- Part of js_top_worker-client package
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Filter identifiers in capture_runtime_values to only capture values,
not exceptions, modules, or types. This prevents "Fatal error: X unbound
at toplevel" messages from Toploop.getvalue.
- Change environment logging from INFO to DEBUG level
- Change unix_worker log level from INFO to WARNING
- Update test expected outputs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add idl/message.ml with typed JSON message protocol for client-worker
communication (Init, Eval, Complete, TypeAt, Errors, CreateEnv, DestroyEnv)
- Rewrite lib/worker.ml to use message handlers instead of RPC server stubs
- Add multi-universe support to findlibish.ml for loading META files from
multiple findlib_index sources with cycle detection
- Update node test expected files for new output format
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When running under dune exec, packages may be installed in different
directory trees (dune install vs opam). Fpath.relativize produces paths
with ".." in these cases, which breaks the output directory structure.
The fix detects ".." in relativized paths and falls back to extracting
path components after the "lib" directory.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When specified, builds all packages from ocamlfind list instead of
requiring explicit package names on the command line.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace the two-field format (meta_files + universes) with a single
"metas" field containing all META paths for the dependency closure.
- Remove recursive universe loading from findlibish.ml
- Each package's findlib_index now lists all transitive META paths
- opam_all builds correct META paths using ocamlfind metadata
- Fixes incorrect path generation for subpackages (e.g., base.shadow_stdlib)
This simplifies client loading: one fetch gets all needed META paths,
no recursive findlib_index resolution required.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New blog posts (monopam-madness, open-source-and-ai, weeknotes-2026-10),
notebook showcase with card layout and screenshots, Atom feed generator,
foundations notebook fixes, ONNX test improvements, widget interaction
tests, deploy script updates for oxcaml switch, and .gitignore for
build artifacts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of requiring every .mld file to specify @x-ocaml.universe and
@x-ocaml.worker tags individually, configure the default universe path
once in dune-workspace (--config x-ocaml.universe=/_opam). The shell
emits <meta> tags from config values, and per-page @x-ocaml tags can
still override them.
Changes:
- dune-workspace: add --config x-ocaml.universe=/_opam to html_flags
- gen_rules.ml: pass --config to odoc html-generate for @site build
- odoc_jon_shell.ml: emit <meta> tags from x-ocaml.* config values
- odoc generator.ml: pass config to shell page_creator
- interactive_extension.ml: upsert meta tags (update existing or create)
- x_ocaml.ml: infer jtw backend from x-ocaml-universe meta tag
- Remove @x-ocaml.universe/@x-ocaml.worker from 14 .mld files using
the default /_opam universe
- deploy-site.sh: add dune install x-ocaml, chmod fix, widget-leaflet
- findlibish.ml: module detection fallback via jsoo runtime
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests the full end-to-end flow of runtime preloaded package detection:
- Preloaded package (yojson): succeeds without fetching .cma.js
- Normal package (stringext): fetches and loads from universe
- CRC mismatch (crc_conflict): raises Crc_mismatch with bogus CRC
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add symtable_memo and crc_memo hash tables to Impl for caching
module availability and CRC lookups (both binary and server side)
- Extract pure check_preload_status function into Impl for testability
- Capture server-side CRCs from fetched .cmi files in add_dynamic_cmis_sync
- Raise Crc_mismatch exception (instead of returning false) when a
preloaded package has different CRCs than the universe
- Add 8 ppx_expect tests covering: match, mismatch, partial load,
empty, missing CRCs, server CRC priority, single mismatch in group
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bake module CRCs into dynamic_cmis.json when building universes, then
verify at require-time that preloaded modules match the universe version.
Three defensive checks:
- All modules loaded: package is preloaded (skip import)
- No modules loaded: package is not preloaded (import normally)
- Partial: warn and import (something is wrong)
- CRC mismatch: warn and import (version skew between binary and universe)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove bisect_ppx from odoc (opam dep + 11 instrumentation stanzas)
- Remove unix and findlib from js_top_worker-unix.opam (not opam packages)
- Remove bisect_ppx, findlib, unix from root dune-project
- Add mdx with :with-test guard
- Delete experiments/widget-bridge (stale, removed lwd/note deps)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ppxlib (~5.5MB of bytecode) was statically linked into every worker.js,
even though most users never use PPX rewriters. Replace the custom
JsooTopPpx module with the standard OCaml toplevel mechanism:
Ast_mapper.register + Toploop.preprocess_phrase. PPX packages are now
loaded on-demand via #require, with ppxlib_register bridging ppxlib
into the Ast_mapper pipeline.
Worker size: 67MB → 56MB (11MB / 16% reduction).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add cppo preprocessing for merlin-js and x-ocaml workers to support
conditional compilation with OXCAML flag
- Guard day10 packages with enabled_if >= 5.3.0 since they need recent OCaml
- Remove fatal odoc warnings from dune-workspace (handled per-package now)
- Bump merlin-js dune lang to 3.17
- Add warning suppression flags where needed (-w -58, -w -67)
- Add interactive extension exercise pages (FOCS 2020/2024/2025, OxCaml
stack allocation)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add managed widget protocol (display_managed, command, register_adapter)
for external widget adapters like Leaflet maps
- Extract Leaflet map adapter into separate js_top_worker-widget-leaflet
library, loadable via #require
- Add widget rendering to x-ocaml web component (widget_render.ml) so
widgets work in .mld documentation pages
- Wire widget callbacks through OCaml client (js_top_worker_client_msg.ml)
- Complete the preloaded list in findlibish.ml to match all transitive
worker dependencies, preventing "file already exists" errors when
#require loads packages already compiled into the worker
- Add demo_widgets.mld and demo_map.mld documentation pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Widget.View re-export of Widget_view for toplevel access
- Copy ocaml-worker.js to build output via dune rule
- Use worker.bc.js for local dev testing
- Update test code to use Widget.View instead of Widget_view
- Add diagnostic eval and error logging to test page
All four widget tests now pass in browser: static widget,
interactive counter, slider, and cross-cell signal propagation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add js_top_worker-widget and note to the example worker's dependencies,
and create widget_test.html with three interactive test cases: a static
widget, an FRP counter with increment/decrement buttons, and a slider
with a cross-cell derived display.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Initialize Widget.set_sender at worker startup so widget view updates
are sent via Worker.post_message. Handle incoming WidgetEvent messages
by routing them through Widget.handle_event. Add WidgetUpdate/WidgetClear
catch-all cases in the OCaml client to suppress non-exhaustive match
warnings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add widget_update and widget_clear message handling to _handleMessage,
onWidgetUpdate/onWidgetClear callbacks to constructor options, and
sendWidgetEvent method for sending widget events to the worker.
Update TypeScript declarations with corresponding interfaces and types.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix sidebar kindBadge: map leaf-page→pg, module-type→MT, etc. (was
showing "L" for leaf-page entries)
- Stop escaping sidebar content HTML (entries contain <code> tags)
- Fix inline sidebar JSON: use Html.cdata_script instead of Html.txt
to prevent HTML-escaping inside <script> tags
- Add --xo-* CSS custom properties for x-ocaml cells in light/dark themes
- Fix support file registration: use 'opam var share' instead of
'opam var x-ocaml:share' (works without x-ocaml being an opam package)
- Suppress empty <li> from config-only extension tags (@x-ocaml.*)
- Add worker_url field to jtw opam findlib_index.json
- Refactor x-ocaml.js worker URL discovery to support both direct
worker_url and day10-style version/content_hash paths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove 12 JS stubs from js_top_worker that are already provided by
basement/runtime.js and base/runtime.js (blocking_mutex, blocking_condition,
thread_yield, basement_dynamic, basement_alloc_stack_bind, caml_ml_domain_index)
- Keep caml_make_local_vect as it's needed by OxCaml compiler-libs and base
is not a transitive dependency
- Fix free-variables warnings by using proper //Provides/Requires pattern
for domain TLS shared state
- Add (link_flags (-linkall)) to odoc-scrollycode-extension test binary so
Html_page's side-effect shell registration is linked (matches real odoc binary)
- Promote test expected outputs for OCaml 5.4.1 and scrollycode extension changes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- findlibish.mli: use Js_top_worker.Impl.dynamic_cmis (RPC module removed)
- worker.ml: use Impl.dcs_url instead of Toplevel_api_gen.dcs_url
- x-ocaml/src/jtw_client: convert to cppo for OxCaml-only
ppx_template_generated field in Query_protocol.Compl
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Consolidate js_top_worker and odoc dual-compiler stanzas into single
library stanzas with cppo rules generating impl.ml from impl.cppo.ml
- Per-package findlib_index.json with relative universe paths (../dep)
and implicit stdlib dependency injection
- Add find_stdlib_dcs to Impl.S interface for stdlib CMI lookup via
findlib metadata instead of hardcoded URLs
- Replace jsoo Json.output/Json.unsafe_input with plain JSON.stringify/
JSON.parse for cross-jsoo-version compatibility (6.0.1+ox vs 6.2.0)
- Cross-origin worker support: set __global_rel_url in blob worker,
skip URL rewriting for absolute http(s) URLs
- Fix odoc doc comments and ocamlformat-ignore for cppo files
- Add demo docs, helper scripts, and x-ocaml package-lock.json
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The project migrated from rpclib/ppx_deriving_rpc JSON-RPC to a simple
message-passing protocol but the old RPC infrastructure remained wired
in. This removes it entirely (~5400 lines deleted):
- Move API types from Toplevel_api_gen into Impl, replace Rpc_lwt.ErrM
with plain Lwt + result
- Replace Jsonrpc/Rpcmarshal JSON serialization with Yojson.Safe
- Rewrite all tests to call Impl.Make(S) directly instead of via RPC
server/client roundtrip
- Rewrite examples and browser tests to use message protocol client
- Delete RPC source files, _old/ directory, and dead opam packages
- Remove rpclib dependencies from all dune and opam files
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable loading .cma.js files from a different origin (e.g., ocaml.org)
by working around Chrome's CORB which blocks cross-origin importScripts
for files with embedded binary CMI data.
worker.ml: detect cross-origin URLs in import_scripts and use
synchronous XHR + eval() instead of importScripts. Same-origin
URLs continue to use the standard path.
jtw_client.ml: create blob: URL wrapper for cross-origin worker.js
(browsers block cross-origin Worker construction), derive stdlib_dcs
URL from findlib_index base, switch to eval_stream for streaming
phrase-by-phrase output.
interactive_extension.ml: always load x-ocaml.js and worker.js from
local _x-ocaml/ path (same-origin), communicate universe URL via
<meta> tag. Set backend to "jtw" when a universe is configured.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add --copy-file flag to jtw opam/opam-all for including x-ocaml.js
and other assets in universe output
- Pass findlib_requires and findlib_index from meta tags through to
the JTW worker init, so @x-ocaml.requires packages are loaded
during setup
- x_ocaml.ml reads <meta name="x-ocaml-packages"> and
<meta name="x-ocaml-universe"> before creating the backend
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Writers (jtw.ml opam mode, jtw_gen.ml day10 mode): output filename
changed from findlib_index to findlib_index.json, JSON key from
"metas" to "meta_files".
Reader (findlibish.ml): universe link resolution uses .json extension.
Runtime default (impl.ml): changed from "findlib_index" to
"findlib_index.json".
JS client, test fixtures, HTML test pages, and documentation updated
to match.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Escape curly braces and fix odoc reference syntax to eliminate warnings
with (warnings fatal):
- Replace {dir}, {pkg}, {hash} etc with [dir], [<pkg>], [<hash>] or
{[ code blocks ]} as appropriate
- Fix {!Stdlib.Out_channel.with_open_gen} -> [Out_channel.with_open_gen]
in sherlodoc type_polarity.mli
- Fix @scrolly.<theme> -> [@scrolly.<theme>] in scrollycode extension
- Fix JSON format in findlibish.ml doc comment
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add comprehensive JS stubs for OxCaml-specific primitives (domain TLS,
arch detection, blocking sync, basement/capsule) needed by the OxCaml
js_of_ocaml runtime
- Fix demo.js to load rpc_worker.bc.js (JSON-RPC) instead of the
non-RPC _opam/worker.js, fixing a protocol mismatch bug
- Fix exec RPC method never resolving: rename phrase_p parameter from
~name:"string" to unnamed, preventing rpclib from incorrectly treating
the phrase as a named parameter in the dispatch dict
- Remove unused cbort, zarith, bytesrw dependencies from opam and
dune-project
- Bump dune version in x-ocaml opam files to 3.21 for OxCaml support
- Update cram test expected output for current package list
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add support for building js_top_worker and odoc with both the standard
OCaml 5.4 compiler and the OxCaml 5.2.0+ox compiler using cppo
conditional compilation and dual dune stanzas.
js_top_worker changes:
- Bump dune-project to 3.21 for %{ocaml-config:ox} support
- Add dual library stanzas gated by (enabled_if %{ocaml-config:ox})
- Add cppo guards for OxCaml API differences:
- Compilation_unit.Name.t vs string for persistent loader
- Env.report_error ~level:0 (extra parameter)
- Language_extension.set_universe_and_enable_all (oxcaml-only)
- Unit_info.make ~for_pack_prefix (extra parameter)
- Typemod.type_implementation (extra Compilation_unit arg)
- Gate ppx_deriving_rpc with (not %{ocaml-config:ox})
odoc changes:
- Apply upstream oxcaml PR #1399 (art-w/upstream-oxcaml)
- Bump dune-project to 3.21
- Add dual stanzas in loader, model, xref2, odoc, syntax_highlighter
- Add cppo OXCAML guards for compiler API differences
- Support OxCaml features: modes, layouts, labeled tuples, iarray,
unboxed records, module type strengthening, polymorphic arguments,
call position arguments, Import_info.t, Compilation_unit.t
Verified end-to-end: scrollycode demos generate HTML and the
interactive playground evaluates OCaml code in the browser with
both compiler switches.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix client.ml absolute_url to handle root-relative paths (/ prefix)
using window.location.origin instead of page directory path
- Abstract merlin_ext.ml to use a post function closure instead of
concrete Client.t, decoupling from specific backend
- Update cell.ml/mli to accept eval/fmt/post function closures
instead of Client.t, and split init/start to avoid synchronous
response race condition with jtw backend
- Wire x_ocaml.ml to read backend attribute and dispatch through
Backend module (jtw or builtin)
- Add W.setup call after W.init in jtw_client to load stdlib
- Create rpc_worker.ml: full-featured JSON-RPC worker combining
the complete S module (findlibish, stdlib) with JSON-RPC protocol
Verified: code execution and Merlin type-on-hover both work in the
scrollycode playground overlay (hovering shows type tooltips like
"type bool = false | true").
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch OcamlWorker from fromManifest() to fromIndex(), which reads
compiler version and content_hash directly from the per-universe
findlib_index. This removes the dependency on a global manifest.json
and naturally supports multiple OCaml versions.
Update all HTML test pages and runner to use the new API, refresh
universe hashes to match content-addressed output, and expand
tutorial test definitions and Playwright specs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests per-solution OCaml version support: containers.3.14 requires
ocaml < 5.4 and is solved with 5.3.0, verifying the worker loads the
correct compiler and stdlib without inconsistent assumptions errors.
Also updates universe hashes to match content-addressed output.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add OcamlWorker.fromManifest() to discover content-hashed worker URLs
from manifest.json, and update all test pages to use it instead of
hardcoded compiler paths. This enables Cache-Control: immutable for
all artifact paths except manifest.json and findlib_index.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add browser-based integration tests and 30 interactive tutorials for
Daniel Bunzli's OCaml libraries, exercising the JTW (js_top_worker)
system with real opam packages compiled to JavaScript.
Tutorials cover Fmt, Cmdliner, Mtime, Logs, Uucp, Uunf, Astring,
Jsonm, Xmlm, Ptime, React, Hmap, Gg, Vg, Note, Otfm, Fpath, Uutf,
B0, and Bos across multiple versions, testing API evolution.
Also fixes incremental output accumulation in the client library and
adds setup documentation for reproducing the demo environment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace CBOR/channel-based transport with direct message passing.
Add OutputAt message type for incremental cell output streaming.
Remove unused channel.ml/mli and rpc_cbor.ml/mli modules.
Update client libraries with worker blob URL creation helper.
Add node-based incremental output test.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Browser tests:
- Add dune configuration for browser tests with Playwright
- Fix test_worker.ml to include js_of_ocaml-toplevel library
(required for toplevel initialization)
- Register all RPC methods in test worker
- Tests run via `dune build @runbrowser`
Cell dependency tests:
- Add node_dependency_test.ml with 26 tests covering:
- Linear dependencies (c1 → c2 → c3 → c4)
- Diamond dependencies (d1 → d2,d3 → d4)
- Missing dependency error handling
- Type update propagation
- Type shadowing across cells
- Complex module dependency graphs
- Key finding: dependencies are explicit, not transitive
Also adds docs/test-gaps-design.md documenting test coverage
gaps and implementation plan.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Restore comprehensive directives test (850+ lines) that was temporarily disabled
- Update expected outputs for current environment (OCaml 5.4.0)
Test infrastructure improvements:
- Socket path configurable via JS_TOP_WORKER_SOCK environment variable
- Worker forks: parent blocks until child is ready, then prints child PID and exits
- Child redirects stdout/stderr to /dev/null so shell $() capture completes
- No polling, no sleeps - deterministic pipe-based synchronization
- Each test uses unique socket path for parallel test isolation
Usage:
WORKER_PID=$(unix_worker) # Blocks until ready, returns child PID
unix_client init ... # Guaranteed to connect immediately
kill $WORKER_PID # Clean shutdown
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
JavaScript client (client/ocaml-worker.js):
- ES module with async/await API for web applications
- TypeScript declarations (ocaml-worker.d.ts)
- Supports init, eval, complete, typeAt, errors, createEnv, destroyEnv
OCaml client (js_top_worker_client_msg):
- Uses new message protocol instead of RPC
- Lwt-based async API matching the JS client
- Part of js_top_worker-client package
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Filter identifiers in capture_runtime_values to only capture values,
not exceptions, modules, or types. This prevents "Fatal error: X unbound
at toplevel" messages from Toploop.getvalue.
- Change environment logging from INFO to DEBUG level
- Change unix_worker log level from INFO to WARNING
- Update test expected outputs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add idl/message.ml with typed JSON message protocol for client-worker
communication (Init, Eval, Complete, TypeAt, Errors, CreateEnv, DestroyEnv)
- Rewrite lib/worker.ml to use message handlers instead of RPC server stubs
- Add multi-universe support to findlibish.ml for loading META files from
multiple findlib_index sources with cycle detection
- Update node test expected files for new output format
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When running under dune exec, packages may be installed in different
directory trees (dune install vs opam). Fpath.relativize produces paths
with ".." in these cases, which breaks the output directory structure.
The fix detects ".." in relativized paths and falls back to extracting
path components after the "lib" directory.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace the two-field format (meta_files + universes) with a single
"metas" field containing all META paths for the dependency closure.
- Remove recursive universe loading from findlibish.ml
- Each package's findlib_index now lists all transitive META paths
- opam_all builds correct META paths using ocamlfind metadata
- Fixes incorrect path generation for subpackages (e.g., base.shadow_stdlib)
This simplifies client loading: one fetch gets all needed META paths,
no recursive findlib_index resolution required.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>