servo WebIDL Python codegen is incompatible with Nix hermetic sandbox.
Build weft-servo-shell and weft-app-shell without servo-embed feature
so the VM infrastructure compiles cleanly. The full servo-embed build
is performed separately via cargo on a Linux host.
Add oxalica/rust-overlay flake input; override rustPlatform in
weft-packages.nix with cargo/rustc from rust-bin.stable.1.93.0;
apply overlay in both devShell and nixosConfigurations.weft-vm.
Fixes build failure where nixos-25.05 Rust 1.86.0 was below the
rust-version requirement of wasmtime and other dependencies.
- weft-packages.nix: add weft-servo-shell and weft-app-shell with servo-embed
feature; real sha256 hashes for servo (8e7dc40) and stylo (dca3934) git deps
computed via nix-prefetch-git; add clang/cmake/python3 as native build inputs
for servo packages; set LIBCLANG_PATH; disable doCheck for VM builds
- configuration.nix: import virtualisation/qemu-vm.nix for system.build.vm;
replace hardware.opengl with hardware.graphics (NixOS 24.11); add
weft-servo-shell systemd user service; add servo-shell/app-shell/pack to
environment packages
- infra/vm/build.sh: switch to system.build.vm target (qcow2 attribute not
provided by default NixOS modules)
- infra/vm/run.sh: invoke the VM script produced by system.build.vm
- flake.nix, infra/nixos/: NixOS VM with Mesa, virtio-gpu, Wayland,
systemd user services for compositor and session supervisor
- infra/vm/: QEMU build and run scripts
- .github/workflows/ci.yml: add Linux job to type-check weft-servo-shell
and weft-app-shell with --features servo-embed
- docs/architecture.md, docs/security.md, docs/building.md: replace
stale pre-implementation design documents
- README.md: rewrite to reflect current codebase
- crates/weft-servo-shell/SERVO_PIN.md: update implementation status and add
SpiderMonkey process boundary statement
WappPackage and AppInfo both gain a version field. scan_installed_apps()
reads it from wapp.toml and includes it in InstalledApps responses.
system-ui.html shows it in the title tooltip as 'com.example.app v1.0.0'.
All roundtrip and integration tests updated.
When weft-appd restarts, session IDs reset to 0. Without clearing,
RUNNING_APPS repopulation after reconnect would coexist with stale
entries from the previous session. Removing all weft-taskbar-app
elements on the open event ensures the taskbar reflects only the
current appd session registry.
ensureTaskbarEntry() now creates a label span and an inline x close
button. The x button is hidden until the taskbar entry is hovered, then
sends TERMINATE_APP via WebSocket on click. CSS for weft-taskbar-app
and .task-close added (flex layout, hover reveal, red tint on x hover).
system-ui.html: APP_READY handler extracts the last component of
msg.app_id (e.g. 'notes' from 'com.example.notes') and shows
'<name> is ready'. Falls back to the session_id if app_id is absent.
system-ui.html: LAUNCH_ACK handler now passes msg.app_id to
ensureTaskbarEntry so the taskbar label shows the app name
immediately on launch, matching the behaviour of RUNNING_APPS.
ipc.rs:
- Add SessionInfo { session_id: u64, app_id: String } struct.
- Change RunningApps { session_ids: Vec<u64> } to
RunningApps { sessions: Vec<SessionInfo> } so callers can display
meaningful app names without a follow-up QueryAppState round-trip.
- Add session_info_roundtrip test.
main.rs:
- Add SessionEntry { app_id: String, state: AppStateKind } to store
app_id alongside state in SessionRegistry.
- launch() stores app_id in the entry.
- running_sessions() replaces running_ids(); returns Vec<SessionInfo>.
- state() reads from SessionEntry.state.
- set_state() writes to SessionEntry.state.
- QueryRunning dispatch uses running_sessions().
- Test registry_running_ids_reflects_live_sessions renamed to
registry_running_sessions_reflects_live_sessions and updated to
assert both session_id and app_id fields.
- dispatch_query_running test asserts app_id values are present.
system-ui.html:
- RUNNING_APPS handler uses msg.sessions[].{session_id,app_id}.
- ensureTaskbarEntry(sessionId, appId): shows the last component of the
reverse-domain app ID as the taskbar label; sets data-app-id attribute;
tooltip shows full app ID and session number.
- LAUNCH_ACK handler passes null for appId (session ID only available
at launch time; app_id arrives in RUNNING_APPS on reconnect).
Implements the weft-appd WebSocket server that allows the system-ui.html
page running inside Servo to send requests and receive push notifications
without requiring custom SpiderMonkey bindings.
ws.rs — WebSocket connection handler:
- Accepts a tokio TcpStream, performs WebSocket handshake via
tokio-tungstenite accept_async.
- Reads JSON Text frames, deserializes as Request (serde_json), calls
dispatch(), sends Response as JSON Text.
- Subscribes to a broadcast::Receiver<Response> for server-push
notifications (APP_READY, etc.); forwards to client via select!.
- Handles close frames, partial errors, and lagged broadcast gracefully.
main.rs — server changes:
- broadcast::channel(16) created at startup; WebSocket handlers
subscribe for push delivery.
- TcpListener bound on 127.0.0.1:7410 (default) or WEFT_APPD_WS_PORT.
- ws_port() / write_ws_port(): port written to
XDG_RUNTIME_DIR/weft/appd.wsport for runtime discovery.
- WS accept branch added to the main select! loop alongside Unix socket.
ipc.rs — Response and AppStateKind now derive Clone (required by
broadcast::Sender<Response>).
system-ui.html — appd WebSocket client:
- appdConnect(): opens ws://127.0.0.1:<port>/appd with exponential
backoff reconnect (1s → 16s max).
- On open: sends QUERY_RUNNING to populate taskbar with live sessions.
- handleAppdMessage(): maps LAUNCH_ACK and RUNNING_APPS to taskbar
entries; APP_READY shows a timed notification; APP_STATE::stopped
removes the taskbar entry.
- WEFT_APPD_WS_PORT window global overrides the default port.
New deps: tokio-tungstenite 0.24, futures-util 0.3 (sink+std),
serde_json 1.
New crate implementing the application daemon entry point:
- crates/weft-appd/Cargo.toml: tokio (current-thread runtime), anyhow,
sd-notify, tracing dependencies
- crates/weft-appd/src/main.rs: async run() resolves IPC socket path
from WEFT_APPD_SOCKET or XDG_RUNTIME_DIR/weft/appd.sock; stubs for
AppRegistry, IpcServer, CompositorClient, RuntimeSupervisor,
CapabilityBroker, ResourceController per WEFT-OS-APPD-DESIGN.md;
sd_notify(READY=1) to be sent after IpcServer bind + CompositorClient
connect
- infra/systemd/weft-appd.service: Type=notify, Requires+After
weft-compositor.service, After servo-shell.service
Also fix two winit backend issues that were present in the working tree:
- remove spurious mut on display binding (never mutated after init)
- wrap std::env::set_var in unsafe block (required since Rust 1.80)
Includes winit Wayland input audit for servo-shell integration planning.
New files:
- crates/weft-servo-shell/: new workspace member
- Cargo.toml: anyhow + tracing deps; no servo dep yet (requires git
dependency on github.com/servo/servo with multi-minute build; deferred
until embedder contract is confirmed)
- src/main.rs: reads WAYLAND_DISPLAY and WEFT_SYSTEM_UI_HTML, locates
system-ui.html from packaged path, calls embed_servo() stub that
returns a descriptive error explaining the integration work remaining
- infra/shell/system-ui.html: system UI document per blueprint Section 5
DOM structure (weft-desktop, weft-wallpaper, weft-taskbar, weft-launcher,
weft-notification-center, weft-window); includes clock and launcher toggle
- infra/systemd/servo-shell.service: Requires+After weft-compositor.service,
Type=simple, Restart=on-failure
- docs/architecture/winit-wayland-audit.md: audit of winit 0.30.x Wayland
backend against WEFT input requirements; identifies keyboard shortcut
inhibit gap, touch gesture gap, IME incomplete (zwp_text_input_v3),
frame pacing absent (wp_presentation_time), DMA-BUF unverified;
none block initial integration; all tracked as pre-GA work items
Modified:
- Cargo.toml: add weft-servo-shell to workspace members
- scripts/wsl-check.sh: switch to --workspace for all three gates