commits
Writers (jtw.ml opam 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>
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>
- Remove CBOR transport, keep JSON-RPC only for browser compatibility
- Remove obsolete cbor and channel test infrastructure
- Add interactive demo (demo.html/demo.js) with README documentation
- Add Playwright browser tests for demo, features, and environment isolation
- Enhance jtw tool with --path and --deps options for library compilation
- Improve findlib path handling for dynamic CMI loading
- Update node tests with proper expected output files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ppx_deriving.runtime to _opam packages via jtw opam command
- Update PPX tests to use #require "ppx_deriving.runtime" before derivers
- Tests now verify actual ppx_deriving functionality:
- [@@deriving show] generates working show_*/pp_* functions
- [@@deriving eq] generates working equal_* functions
- Combined derivers work together
- Module support with derivers
- Update all expected files for new ppx_deriving findlib entries
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The PPX tests now verify that:
- ppx_deriving.show/eq transforms code (generates runtime references)
- Unknown derivers produce appropriate ppxlib errors
- Normal code and attributes work through the PPX pipeline
- Modules and functors are supported
Added ppx_deriving.show, ppx_deriving.eq, and ppx_deriving.runtime
to test dependencies.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
CI runs on Ubuntu Linux with OCaml 5.2 and 5.3, including Node.js
tests.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests verify the MIME output API is correctly wired up:
- exec_result.mime_vals field is present and returns a list
- mime_val type has mime_type, encoding (Noencoding/Base64), and data fields
- Multiple executions have independent mime_vals
- exec_toplevel also returns mime_vals
The mime_printer library is already integrated and supports:
- SVG images (Noencoding)
- Base64-encoded images (PNG, JPEG, etc.)
- Text/HTML and other MIME types
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests for the multiple environments feature:
- Creating and destroying environments
- Environment isolation (values don't leak between environments)
- Listing environments
- Reusing environment names after destruction
All 21 tests verify that environments are properly isolated using
Toploop.toplevel_env save/restore mechanism.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit adds support for multiple isolated OCaml execution environments,
each with its own type environment and failed cell tracking.
Key changes:
- New Environment module (lib/environment.ml) provides:
- Isolated execution contexts using Toploop.toplevel_env
- Per-environment state (is_setup, failed_cells)
- Create/destroy/list operations
- with_env for safe context switching
- Updated API to include env_id parameter on all environment-scoped operations
- Changed env_id from string option to string (empty = default) for cmdliner compatibility
- Updated all clients, workers, tests, and examples
Environment IDs are strings. Empty string maps to "default" environment.
All existing single-environment usage continues to work unchanged.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This adds the Channel module which extends the RPC model to support:
- Push messages from server to client (one-way notifications)
- Event messages from client to server (widget interactions)
Message types:
- Request: client → server (expects response, like RPC)
- Response: server → client (matches request ID)
- Push: server → client (stdout/stderr streaming, widget updates, progress)
- Event: client → server (widget events)
Push kinds:
- Output: streaming stdout/stderr
- Widget_update: widget state changes
- Progress: task progress notifications
- Custom_push: extensible custom push types
Event kinds:
- Widget_event: user interactions (clicks, input changes)
- Custom_event: extensible custom event types
All messages use CBOR encoding for efficient binary transport.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update lib/worker.ml to use Transport.Cbor for encoding/decoding
- Update idl/js_top_worker_client.ml to use CBOR transport
- Update idl/js_top_worker_client_fut.ml to use CBOR transport
- Update example/unix_worker.ml to use CBOR and fix partial read issue
- Update example/unix_client.ml to use CBOR transport
- Add comprehensive directive tests (test/cram/directives.t)
The CBOR transport provides more compact binary encoding compared to
JSON-RPC, which is beneficial for web worker communication.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Integrate ppxlib's Driver.map_structure into the toplevel's PPX
preprocessing, supporting both old-style Ast_mapper PPXs (like
js_of_ocaml's Ppx_js) and modern ppxlib-based PPXs.
Changes:
- Add ppxlib as a dependency in lib/dune
- Modify JsooTopPpx to chain old-style mappers with ppxlib Driver
- Handle AST version conversion between compiler's Parsetree and
ppxlib's internal AST using Selected_ast.of_ocaml/to_ocaml
- Fix typecheck_phrase to use JsooTopPpx.preprocess_phrase for
consistency with execute (was using Toploop.preprocess_phrase)
- Add node-based PPX test verifying the preprocessing pipeline
The preprocessing order is: old-style Ast_mapper rewriters first,
then ppxlib transformations. This allows both types of PPXs to
coexist and be applied correctly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive test suite for toplevel directives running in Node.js:
- #show, #show_type, #show_val, #show_module, #show_exception
- #print_depth, #print_length
- #install_printer, #remove_printer
- #warnings, #warn_error
- #rectypes, #directory, #help, #labels, #principal
- Error cases for unknown directives and missing identifiers
Fixes to test infrastructure:
- Use %{lib:js_top_worker:stubs.js} instead of +js_top_worker/stubs.js
(the + syntax requires an installed package, not a local one)
- Remove stderr flusher in capture function (causes hangs in js_of_ocaml)
- Restore stdout flusher after capture so Printf.printf works for test output
29/31 tests pass; 2 known failures where errors go to stderr rather
than being captured in result.script.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The unix_worker was crashing at startup with:
Fatal error: cannot load shared library dllos_ipc_stubs
Reason: undefined symbol: caml_uerror
This happened because merlin-lib's os_ipc C stubs depend on caml_uerror
from the Unix library, but in bytecode mode the stubs are loaded
dynamically and the Unix runtime wasn't available yet.
Fix by adding `unix` library explicitly to unix_worker dependencies,
ensuring the Unix C stubs are loaded before os_ipc_stubs.
Also update expected output for OCaml 5.4.0:
- Version string: 5.2.0 -> 5.4.0
- Compiler flag: transparent_modules -> no_alias_deps
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Organize impl.ml with odoc-style section comments to improve navigation
and understanding. The module is now divided into clear sections:
- {1 OCaml Toplevel Implementation} - Module overview
- {2 Cell Dependency System} - Cell ID → module wrapping
- {2 PPX Preprocessing} - JsooTopPpx module
- {2 Backend Signature} - Module type S
- {2 Main Functor} - Make(S) containing:
- {3 State} - Mutable refs
- {3 Lexer Helpers} - refill_lexbuf
- {3 Setup and Initialization} - exec', setup
- {3 Output Helpers} - buffer utilities
- {3 Phrase Execution} - execute, typecheck
- {3 Dynamic CMI Loading} - add_dynamic_cmis
- {3 RPC Handlers} - init, setup, exec, etc.
- {3 Merlin Integration} - completion, errors, type_enclosing
This makes the ~900 line file more navigable without changing functionality.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The JsooTopPpx module was set up to capture PPX registrations and apply
rewriters, but the preprocess_phrase function was never called during
execution. This commit:
- Adds JsooTopPpx.preprocess_phrase call before Toploop.execute_phrase
- Removes debug output from preprocess_structure
This enables PPX rewriters (including Ppx_js for [%js] syntax) to work
properly in the toplevel.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix duplicate Buffer.clear call (line 251-252 was clearing code_buff twice)
- Remove unused `complete` function (just "Not implemented")
- Remove unused `split_primitives` function (leftover from removed compile_js)
These are non-breaking changes that reduce dead code in impl.ml.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The compile_js method for ahead-of-time JS compilation is out of scope
for this interactive toplevel tool. Remove it from:
- API definition (toplevel_api.ml, toplevel_api_gen.ml)
- Implementation (impl.ml)
- Worker registrations (worker.ml, unix_worker.ml)
- Client libraries (js_top_worker_client.ml/mli, js_top_worker_client_fut.ml)
- Tests (node_test.ml, unix_test.ml)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The cbort library depends on zarith which needs JavaScript stubs
when compiled to js_of_ocaml. Add zarith_stubs_js library and its
runtime.js to enable Node.js testing.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement type-safe CBOR codec for Rpc.t values using the cbort library,
providing a compact binary alternative to JSON-RPC encoding.
- Add rpc_cbor module with tagged encoding for Rpc.t variants
- Add transport abstraction with Json, Cbor, and Auto implementations
- Add cbort dependency (pinned from tangled.org)
- Clean up duplicate entries in findlibish preloaded list
- Add comprehensive tests for CBOR encoding/decoding
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This change leverages js_of_ocaml's --toplevel --include-runtime flags
(from PR #1509) to embed JS stubs directly into each library's compiled
JavaScript file, rather than requiring them to be bundled in the main
worker/toplevel.
Key changes:
- Add ~import_scripts parameter to Findlibish.require for configurable
JS loading
- Compile library archives with --toplevel --include-runtime --effects=cps
to embed stubs
- Add jsoo_runtime query function to Ocamlfind module
- Update test to use base library and verify stubs work at runtime
- Fix OCaml 5.4/opam 2.5 API compatibility issues
The stubs are now self-contained in each library file and automatically
registered on jsoo_runtime when the library is loaded via importScripts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Writers (jtw.ml opam 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>
- 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>
- Remove CBOR transport, keep JSON-RPC only for browser compatibility
- Remove obsolete cbor and channel test infrastructure
- Add interactive demo (demo.html/demo.js) with README documentation
- Add Playwright browser tests for demo, features, and environment isolation
- Enhance jtw tool with --path and --deps options for library compilation
- Improve findlib path handling for dynamic CMI loading
- Update node tests with proper expected output files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ppx_deriving.runtime to _opam packages via jtw opam command
- Update PPX tests to use #require "ppx_deriving.runtime" before derivers
- Tests now verify actual ppx_deriving functionality:
- [@@deriving show] generates working show_*/pp_* functions
- [@@deriving eq] generates working equal_* functions
- Combined derivers work together
- Module support with derivers
- Update all expected files for new ppx_deriving findlib entries
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The PPX tests now verify that:
- ppx_deriving.show/eq transforms code (generates runtime references)
- Unknown derivers produce appropriate ppxlib errors
- Normal code and attributes work through the PPX pipeline
- Modules and functors are supported
Added ppx_deriving.show, ppx_deriving.eq, and ppx_deriving.runtime
to test dependencies.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests verify the MIME output API is correctly wired up:
- exec_result.mime_vals field is present and returns a list
- mime_val type has mime_type, encoding (Noencoding/Base64), and data fields
- Multiple executions have independent mime_vals
- exec_toplevel also returns mime_vals
The mime_printer library is already integrated and supports:
- SVG images (Noencoding)
- Base64-encoded images (PNG, JPEG, etc.)
- Text/HTML and other MIME types
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests for the multiple environments feature:
- Creating and destroying environments
- Environment isolation (values don't leak between environments)
- Listing environments
- Reusing environment names after destruction
All 21 tests verify that environments are properly isolated using
Toploop.toplevel_env save/restore mechanism.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit adds support for multiple isolated OCaml execution environments,
each with its own type environment and failed cell tracking.
Key changes:
- New Environment module (lib/environment.ml) provides:
- Isolated execution contexts using Toploop.toplevel_env
- Per-environment state (is_setup, failed_cells)
- Create/destroy/list operations
- with_env for safe context switching
- Updated API to include env_id parameter on all environment-scoped operations
- Changed env_id from string option to string (empty = default) for cmdliner compatibility
- Updated all clients, workers, tests, and examples
Environment IDs are strings. Empty string maps to "default" environment.
All existing single-environment usage continues to work unchanged.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This adds the Channel module which extends the RPC model to support:
- Push messages from server to client (one-way notifications)
- Event messages from client to server (widget interactions)
Message types:
- Request: client → server (expects response, like RPC)
- Response: server → client (matches request ID)
- Push: server → client (stdout/stderr streaming, widget updates, progress)
- Event: client → server (widget events)
Push kinds:
- Output: streaming stdout/stderr
- Widget_update: widget state changes
- Progress: task progress notifications
- Custom_push: extensible custom push types
Event kinds:
- Widget_event: user interactions (clicks, input changes)
- Custom_event: extensible custom event types
All messages use CBOR encoding for efficient binary transport.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update lib/worker.ml to use Transport.Cbor for encoding/decoding
- Update idl/js_top_worker_client.ml to use CBOR transport
- Update idl/js_top_worker_client_fut.ml to use CBOR transport
- Update example/unix_worker.ml to use CBOR and fix partial read issue
- Update example/unix_client.ml to use CBOR transport
- Add comprehensive directive tests (test/cram/directives.t)
The CBOR transport provides more compact binary encoding compared to
JSON-RPC, which is beneficial for web worker communication.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Integrate ppxlib's Driver.map_structure into the toplevel's PPX
preprocessing, supporting both old-style Ast_mapper PPXs (like
js_of_ocaml's Ppx_js) and modern ppxlib-based PPXs.
Changes:
- Add ppxlib as a dependency in lib/dune
- Modify JsooTopPpx to chain old-style mappers with ppxlib Driver
- Handle AST version conversion between compiler's Parsetree and
ppxlib's internal AST using Selected_ast.of_ocaml/to_ocaml
- Fix typecheck_phrase to use JsooTopPpx.preprocess_phrase for
consistency with execute (was using Toploop.preprocess_phrase)
- Add node-based PPX test verifying the preprocessing pipeline
The preprocessing order is: old-style Ast_mapper rewriters first,
then ppxlib transformations. This allows both types of PPXs to
coexist and be applied correctly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive test suite for toplevel directives running in Node.js:
- #show, #show_type, #show_val, #show_module, #show_exception
- #print_depth, #print_length
- #install_printer, #remove_printer
- #warnings, #warn_error
- #rectypes, #directory, #help, #labels, #principal
- Error cases for unknown directives and missing identifiers
Fixes to test infrastructure:
- Use %{lib:js_top_worker:stubs.js} instead of +js_top_worker/stubs.js
(the + syntax requires an installed package, not a local one)
- Remove stderr flusher in capture function (causes hangs in js_of_ocaml)
- Restore stdout flusher after capture so Printf.printf works for test output
29/31 tests pass; 2 known failures where errors go to stderr rather
than being captured in result.script.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The unix_worker was crashing at startup with:
Fatal error: cannot load shared library dllos_ipc_stubs
Reason: undefined symbol: caml_uerror
This happened because merlin-lib's os_ipc C stubs depend on caml_uerror
from the Unix library, but in bytecode mode the stubs are loaded
dynamically and the Unix runtime wasn't available yet.
Fix by adding `unix` library explicitly to unix_worker dependencies,
ensuring the Unix C stubs are loaded before os_ipc_stubs.
Also update expected output for OCaml 5.4.0:
- Version string: 5.2.0 -> 5.4.0
- Compiler flag: transparent_modules -> no_alias_deps
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Organize impl.ml with odoc-style section comments to improve navigation
and understanding. The module is now divided into clear sections:
- {1 OCaml Toplevel Implementation} - Module overview
- {2 Cell Dependency System} - Cell ID → module wrapping
- {2 PPX Preprocessing} - JsooTopPpx module
- {2 Backend Signature} - Module type S
- {2 Main Functor} - Make(S) containing:
- {3 State} - Mutable refs
- {3 Lexer Helpers} - refill_lexbuf
- {3 Setup and Initialization} - exec', setup
- {3 Output Helpers} - buffer utilities
- {3 Phrase Execution} - execute, typecheck
- {3 Dynamic CMI Loading} - add_dynamic_cmis
- {3 RPC Handlers} - init, setup, exec, etc.
- {3 Merlin Integration} - completion, errors, type_enclosing
This makes the ~900 line file more navigable without changing functionality.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The JsooTopPpx module was set up to capture PPX registrations and apply
rewriters, but the preprocess_phrase function was never called during
execution. This commit:
- Adds JsooTopPpx.preprocess_phrase call before Toploop.execute_phrase
- Removes debug output from preprocess_structure
This enables PPX rewriters (including Ppx_js for [%js] syntax) to work
properly in the toplevel.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix duplicate Buffer.clear call (line 251-252 was clearing code_buff twice)
- Remove unused `complete` function (just "Not implemented")
- Remove unused `split_primitives` function (leftover from removed compile_js)
These are non-breaking changes that reduce dead code in impl.ml.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The compile_js method for ahead-of-time JS compilation is out of scope
for this interactive toplevel tool. Remove it from:
- API definition (toplevel_api.ml, toplevel_api_gen.ml)
- Implementation (impl.ml)
- Worker registrations (worker.ml, unix_worker.ml)
- Client libraries (js_top_worker_client.ml/mli, js_top_worker_client_fut.ml)
- Tests (node_test.ml, unix_test.ml)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement type-safe CBOR codec for Rpc.t values using the cbort library,
providing a compact binary alternative to JSON-RPC encoding.
- Add rpc_cbor module with tagged encoding for Rpc.t variants
- Add transport abstraction with Json, Cbor, and Auto implementations
- Add cbort dependency (pinned from tangled.org)
- Clean up duplicate entries in findlibish preloaded list
- Add comprehensive tests for CBOR encoding/decoding
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This change leverages js_of_ocaml's --toplevel --include-runtime flags
(from PR #1509) to embed JS stubs directly into each library's compiled
JavaScript file, rather than requiring them to be bundled in the main
worker/toplevel.
Key changes:
- Add ~import_scripts parameter to Findlibish.require for configurable
JS loading
- Compile library archives with --toplevel --include-runtime --effects=cps
to embed stubs
- Add jsoo_runtime query function to Ocamlfind module
- Update test to use base library and verify stubs work at runtime
- Fix OCaml 5.4/opam 2.5 API compatibility issues
The stubs are now self-contained in each library file and automatically
registered on jsoo_runtime when the library is loaded via importScripts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>