From 249614aa8745cd9cb642afa5c19cacf3edd71707 Mon Sep 17 00:00:00 2001 From: Kayshen-X Date: Fri, 19 Jun 2026 18:39:07 +0800 Subject: [PATCH] refactor(host): move web_static to op-web-daemon (Phase 2, first leaf) Establishes the extraction move pattern: git mv module (+ its asset subdir) -> op-web-daemon, add the op-host-desktop -> op-web-daemon dep edge, register pub mod, repoint consumers (crate::web_static -> op_web_daemon::web_static in main.rs + web_canvas_server.rs), and promote the cross-crate items pub(crate) -> pub (resolve_bundle_dir / handle_static_request / write_static_response / ICONIFY_BRANDS_JSON / StaticReply). web_static (static file serving for the --serve-web daemon) now lives in op-web-daemon. Verified: both crates build; 13 web_static tests pass. 6 more leaves + export + doc_io remain in Phase 2. --- crates/op-host-desktop/Cargo.toml | 4 ++++ crates/op-host-desktop/src/main.rs | 3 +-- crates/op-host-desktop/src/web_canvas_server.rs | 8 ++++---- crates/op-web-daemon/src/lib.rs | 3 +++ .../src/web_static.rs | 10 +++++----- .../src/web_static/index.html | 0 .../src/web_static/missing_bundle.html | 0 7 files changed, 17 insertions(+), 11 deletions(-) rename crates/{op-host-desktop => op-web-daemon}/src/web_static.rs (98%) rename crates/{op-host-desktop => op-web-daemon}/src/web_static/index.html (100%) rename crates/{op-host-desktop => op-web-daemon}/src/web_static/missing_bundle.html (100%) diff --git a/crates/op-host-desktop/Cargo.toml b/crates/op-host-desktop/Cargo.toml index dd5c55615..a91ddb174 100644 --- a/crates/op-host-desktop/Cargo.toml +++ b/crates/op-host-desktop/Cargo.toml @@ -63,6 +63,10 @@ role = "Editor" # render-backend / layout scene paths resolve through op-editor-ui. op-editor-ui = { path = "../op-editor-ui" } op-host-native = { path = "../op-host-native", version = "0.8.0", features = ["gl-host"] } +# Phase 2: the headless daemon crate. The `--serve-web` closure migrates here +# over Phases 2-5; op-host-desktop's serve-web dispatch + GUI residuals call into +# it via `op_web_daemon::*`. +op-web-daemon = { path = "../op-web-daemon" } # Accessibility (#67) — the platform-free `accesskit` core types # (`TreeUpdate` / `ActionRequest` / `ActivationHandler` …) used by the # desktop a11y adapter (`src/a11y.rs`). The OS-specific subclassing diff --git a/crates/op-host-desktop/src/main.rs b/crates/op-host-desktop/src/main.rs index 179759c04..1f9697f9c 100644 --- a/crates/op-host-desktop/src/main.rs +++ b/crates/op-host-desktop/src/main.rs @@ -72,7 +72,6 @@ mod theme_preset_host; mod update_check; mod web_canvas_server; mod web_chat_standard; -mod web_static; mod window_state; use op_host_native::{NativeBackend, SharedSkiaContext, SharedSkiaError, WidgetHostNative}; @@ -949,7 +948,7 @@ fn main() { // headless `--render-shots` rasterizer below, MCP — so they resolve // simple-icons instead of the unknown-glyph fallback dot. Set-once / // idempotent. - op_editor_ui::set_brand_catalog(web_static::ICONIFY_BRANDS_JSON); + op_editor_ui::set_brand_catalog(op_web_daemon::web_static::ICONIFY_BRANDS_JSON); // `--mcp` / `--mcp-http` swap the GUI for an MCP server mode; // when one of those ran, exit instead of opening a window. if mcp_serve::run_cli_if_requested() { diff --git a/crates/op-host-desktop/src/web_canvas_server.rs b/crates/op-host-desktop/src/web_canvas_server.rs index 95d49a338..1c62d622e 100644 --- a/crates/op-host-desktop/src/web_canvas_server.rs +++ b/crates/op-host-desktop/src/web_canvas_server.rs @@ -1082,7 +1082,7 @@ pub fn run_web_canvas(path: Option, port: u16, host: &str) -> Result<() TcpListener::bind((host, port)).map_err(|e| format!("bind {host}:{port}: {e}"))?; let bound = listener.local_addr().map(|a| a.port()).unwrap_or(port); eprintln!("openpencil-desktop --serve-web: listening on {host}:{bound}"); - match crate::web_static::resolve_bundle_dir() { + match op_web_daemon::web_static::resolve_bundle_dir() { Some(dir) => eprintln!( "openpencil-desktop --serve-web: serving web bundle from {}", dir.display() @@ -1182,11 +1182,11 @@ fn serve_one( // Static serving: the host page (`/`) and the wasm-bindgen bundle // (`/pkg/*`). Owns only those paths — everything else falls through. if req.method == "GET" { - let bundle_dir = crate::web_static::resolve_bundle_dir(); + let bundle_dir = op_web_daemon::web_static::resolve_bundle_dir(); if let Some(reply) = - crate::web_static::handle_static_request(&req.path, bundle_dir.as_deref()) + op_web_daemon::web_static::handle_static_request(&req.path, bundle_dir.as_deref()) { - return crate::web_static::write_static_response(stream, &reply).map(|()| false); + return op_web_daemon::web_static::write_static_response(stream, &reply).map(|()| false); } } // SSE live-update stream: the browser shell subscribes and re-syncs whenever diff --git a/crates/op-web-daemon/src/lib.rs b/crates/op-web-daemon/src/lib.rs index a6ae6c78c..66334ce74 100644 --- a/crates/op-web-daemon/src/lib.rs +++ b/crates/op-web-daemon/src/lib.rs @@ -12,3 +12,6 @@ //! `openpencil-docs/superpowers/plans/2026-06-19-op-web-daemon-extraction.md`). //! Both `op-host-desktop` (for its `--serve-web` mode) and a thin //! `op-host-web-server` binary depend on this crate. + +// Phase 2 — host-free leaf modules. +pub mod web_static; diff --git a/crates/op-host-desktop/src/web_static.rs b/crates/op-web-daemon/src/web_static.rs similarity index 98% rename from crates/op-host-desktop/src/web_static.rs rename to crates/op-web-daemon/src/web_static.rs index 1b6553a06..8754f004e 100644 --- a/crates/op-host-desktop/src/web_static.rs +++ b/crates/op-web-daemon/src/web_static.rs @@ -34,7 +34,7 @@ const MISSING_BUNDLE_HTML: &str = include_str!("web_static/missing_bundle.html") /// both (a) registered with the shared icon catalog at native GUI startup and /// (b) served to the web client, which deliberately omits it from the wasm /// bundle to keep the first-load small (see `op_editor_ui::widgets::icon_catalog`). -pub(crate) const ICONIFY_BRANDS_JSON: &str = +pub const ICONIFY_BRANDS_JSON: &str = include_str!("../../op-editor-ui/assets/iconify-catalog-brands.json"); /// Route the web client fetches to load the brand-logo catalog at runtime. @@ -45,7 +45,7 @@ pub(crate) const ICONIFY_BRANDS_PATH: &str = "/assets/iconify-catalog-brands.jso const BUNDLE_ENTRY_JS: &str = "op_host_web.js"; /// A fully-formed static HTTP reply (status + MIME + body bytes). -pub(crate) struct StaticReply { +pub struct StaticReply { pub(crate) status: &'static str, pub(crate) content_type: &'static str, pub(crate) body: Vec, @@ -80,7 +80,7 @@ pub(crate) fn bundle_dir_candidates() -> Vec { /// First candidate directory that actually contains the wasm-bindgen JS /// entry (`op_host_web.js`), or `None` when no bundle is built anywhere. -pub(crate) fn resolve_bundle_dir() -> Option { +pub fn resolve_bundle_dir() -> Option { bundle_dir_candidates() .into_iter() .find(|dir| dir.join(BUNDLE_ENTRY_JS).is_file()) @@ -180,7 +180,7 @@ fn safe_relative_path(file: &str) -> Option { /// (the caller falls through to REST / SSE / JSON-RPC routing). The bundle /// directory is a parameter (already resolved) so the routing is testable /// without mutating process-global env. -pub(crate) fn handle_static_request(path: &str, bundle_dir: Option<&Path>) -> Option { +pub fn handle_static_request(path: &str, bundle_dir: Option<&Path>) -> Option { if path == "/" || path == "/index.html" { return Some(match bundle_dir { Some(_) => StaticReply { @@ -277,7 +277,7 @@ fn html_escape(s: &str) -> String { /// Write a static reply with its own Content-Type (binary-safe body) — the /// JSON-only `write_mcp_http_response` cannot carry `application/wasm`. -pub(crate) fn write_static_response( +pub fn write_static_response( stream: &mut S, reply: &StaticReply, ) -> Result<(), String> { diff --git a/crates/op-host-desktop/src/web_static/index.html b/crates/op-web-daemon/src/web_static/index.html similarity index 100% rename from crates/op-host-desktop/src/web_static/index.html rename to crates/op-web-daemon/src/web_static/index.html diff --git a/crates/op-host-desktop/src/web_static/missing_bundle.html b/crates/op-web-daemon/src/web_static/missing_bundle.html similarity index 100% rename from crates/op-host-desktop/src/web_static/missing_bundle.html rename to crates/op-web-daemon/src/web_static/missing_bundle.html