CLI internals
Zig dispatcher, configuration, servers, compilation, HMR, ownership, and contribution tests.
Following an invocation
The npm launcher identifies the platform and executes the binary. main.zig receives arguments and dispatches the first token to a command module. Each command decides how to interpret the remainder, which is why there is no uniform global flag grammar.
Project commands obtain a WuConfig structure from the loader. This configuration stores its strings in its own arena and exposes deinit to free its memory. This prevents returning views into an already-freed JSON buffer. Discovery is an alternative configuration source, not a step that is always merged with an explicit file.
Module map
| Source path | Responsibility |
|---|---|
src/main.zig |
Dispatcher, version, and Zig test aggregator |
src/cli/ |
Help, banner, terminal mode, menus, and prompts |
src/config/config.zig |
Configuration parsing and writing |
src/config/discovery.zig |
Project heuristics in subdirectories |
src/config/deps.zig |
Consumption of aliases and local toolchains |
src/commands/ |
Use cases and artifact generation |
src/runtime/dev_server.zig |
Listener, routes, modules, and reload bridge |
src/runtime/compile.zig |
Compiler selection and daemon connection |
src/runtime/compiler_daemon.js |
Node compilers and message framing |
src/runtime/transform.zig |
Import, alias, and CSS rewriting |
src/runtime/hypervisor/ |
Watcher and prefix router |
src/runtime/security.zig |
Path validation and HTTP policy |
src/orchestrator/ |
Vite development processes and supervision |
src/util/jobobject.zig |
Child-process lifecycle on Windows |
The presence of src/proxy/server.zig or src/commands/test.zig does not prove they are a command’s active path. To establish that, start at the dispatcher and follow calls instead of inferring capabilities from filenames.
src/runtime/dev/ separates routes, files, imports, CSS, environment, sockets and HMR. module_graph.zig maintains identity and importer-based resolution; project_fs.zig contains file access. catalog.zig, semver.zig and json_doc.zig centralize versions, intersections and manifest writing. deploy.zig and build_cache.zig implement transactional local output replacement and build reuse.
Server and compiler
A request arrives over HTTP, is validated, assigned to an app or the shell, and resolved to a file or dependency. Compilation produces JavaScript; imports are then adapted to the server URLs. App identity must accompany the entire flow to resolve its dependencies, styles, and toolchain.
The daemon maintains a channel over pipes. Requests carry an identifier, compilation type, file, loader, length, and app directory. The response repeats the identifier and transmits code or an error. Lengths frame the content; errors are reduced to a single protocol line.
The protocol multiplexes requests by identifier. compile_pool.zig manages multiple daemons with deadlines and compile_warmup.zig precompiles imports; Angular reuses its incremental compiler. The VFS, previous transform pool and disabled native JSX transformer were removed.
The daemon’s standard output belongs to the protocol. Accidental plugin messages can desynchronize it; the daemon redirects several console levels to its log. The parent checks the response identifier and restarts a desynchronized conversation.
Watcher and router
The hypervisor registers app prefixes in a router and watches project directories. It integrates file-event mechanisms and content caches. Its ownership requires care: when returning the server by value, pointers to internal fields must be bound to the final location. bindRunning handles this lifecycle relationship.
The server coordinates shutdown, connection closure, and the daemon. On Windows, Job Objects help prevent child processes from outliving their owner. This feature requires tests on the real operating system; inspecting code is not equivalent to observing process cleanup on every platform.
Building and testing a change
zig build
zig build test --summary all
npm test
build.zig defines Zig build and test steps. npm test runs the invariants in scripts/check-invariants.mjs and the tests/*.test.cjs files, which check the launcher, daemon protocol, and contracts such as doctor output. Run tests against the binary you just built. The summary shows how many cases ran and which were skipped; browser tests are still needed to validate generated apps.
main.zig explicitly imports modules with tests; invariants check the aggregator and command reference. npm run test:fuzz exercises HTTP, WebSocket, path, JSON, SemVer and import parsers. Releases use ReleaseSafe, checksums and reproducible rebuilds.
For protocol changes, test fragmented messages, multiple requests in one chunk, long errors, and mismatched identifiers. Scaffold changes require generation, compilation, and browser mounting. HTTP changes require testing routes, methods, missing assets, and final response headers.
Implementation references
wu-cli/src/main.zigwu-cli/src/runtime/dev/wu-cli/src/runtime/compile_pool.zigwu-cli/src/runtime/compiler_daemon.jswu-cli/src/runtime/module_graph.zigwu-cli/src/runtime/project_fs.zigwu-cli/src/commands/deploy.zigwu-cli/scripts/check-invariants.mjswu-cli/src/fuzz.zig