You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add CLI argument parsing and headless mode so the browser can run without a window. This is the foundation for e2e testing — headless mode must work from day one. Headless path skips winit entirely (no event loop, no window).
Current State
crates/ie-shell/src/main.rs has a Browser struct implementing winit ApplicationHandler. It creates a maximized window and handles CloseRequested/RedrawRequested. No CLI args, no headless mode.
crates/ie-shell/Cargo.toml depends on all 9 other workspace crates (including Phase 2 crates).
File Changes
src/main.rs — restructure: parse CLI, branch on mode
src/cli.rs — new file, CLI argument definitions
src/app.rs — new file, extract Browser struct from main.rs
src/headless.rs — new file, headless execution path
Cargo.toml — add clap, remove Phase 2 deps
Workspace-level prerequisite
Add to root Cargo.toml[workspace.dependencies]:
clap = { version = "4", features = ["derive"] }
Dependency cleanup in ie-shell/Cargo.toml
Remove Phase 2 crate dependencies to speed up compilation:
#[derive(Parser)]#[command(name = "internet-exploder", about = "A minimal, private-by-default web browser")]pubstructCli{/// Run without a window#[arg(long)]pubheadless:bool,/// URL to navigate to on startup#[arg(long)]puburl:Option<String>,/// Print page source to stdout and exit (requires --headless and --url)#[arg(long, requires_all = ["headless","url"], conflicts_with = "dump_status")]pubdump_source:bool,/// Print HTTP status code to stdout and exit (requires --headless and --url)#[arg(long, requires_all = ["headless","url"], conflicts_with = "dump_source")]pubdump_status:bool,/// Allow plain HTTP navigation (default: HTTPS-only)#[arg(long)]puballow_http:bool,}
Parent: #2
Goal
Add CLI argument parsing and headless mode so the browser can run without a window. This is the foundation for e2e testing — headless mode must work from day one. Headless path skips winit entirely (no event loop, no window).
Current State
crates/ie-shell/src/main.rshas aBrowserstruct implementing winitApplicationHandler. It creates a maximized window and handlesCloseRequested/RedrawRequested. No CLI args, no headless mode.crates/ie-shell/Cargo.tomldepends on all 9 other workspace crates (including Phase 2 crates).File Changes
src/main.rs— restructure: parse CLI, branch on modesrc/cli.rs— new file, CLI argument definitionssrc/app.rs— new file, extractBrowserstruct from main.rssrc/headless.rs— new file, headless execution pathCargo.toml— addclap, remove Phase 2 depsWorkspace-level prerequisite
Add to root
Cargo.toml[workspace.dependencies]:clap = { version = "4", features = ["derive"] }Dependency cleanup in
ie-shell/Cargo.tomlRemove Phase 2 crate dependencies to speed up compilation:
ie-htmlie-cssie-jsie-layoutie-renderie-wasmKeep:
ie-net,ie-dom,ie-sandbox,anyhow,thiserror,tracing,tracing-subscriber,tokio,winit,urlAdd:
clapImplementation
CLI argument parsing (
cli.rs)Clistruct with clap derive:Modeenum:Cli::mode(&self) -> Result<Mode>:headless:urlif present →InvalidUrlon failuredump_source→ DumpSource,dump_status→ DumpStatus, neither → InteractiveMode::Headless { url, action }urlif presentMode::Gui { url }Main restructuring (
main.rs)fn main() -> Result<()>:fn init_tracing()— existing tracing_subscriber setupfn run_gui(url: Option<Url>) -> Result<()>— existing winit event loop code, moved from current mainBrowser app struct (
app.rs)Browserstruct and itsApplicationHandlerimpl hereBrowser::new(url: Option<Url>) -> Self— accepts optional startup URLresumed, handle close/redrawHeadless execution path (
headless.rs)pub fn run_headless(url: Option<Url>, action: HeadlessAction) -> Result<()>:runtime.block_on(async { ... })DumpSource→ placeholder:println!("source dump not yet wired (need ie-net)")+ exit 0DumpStatus→ placeholder:println!("status dump not yet wired (need ie-net)")+ exit 0Interactive→ placeholder:eprintln!("interactive headless mode not yet implemented")+ exit 0Tests
CLI parsing unit tests (in
cli.rs)Use
Cli::try_parse_from(["ie", ...])for testing:Mode::Gui { url: None }--url https://example.com→Mode::Gui { url: Some(https://example.com) }--headless→Mode::Headless { url: None, action: Interactive }--headless --url https://example.com→Mode::Headless { url: Some(...), action: Interactive }--headless --dump-source --url https://example.com→Mode::Headless { action: DumpSource }--headless --dump-status --url https://example.com→Mode::Headless { action: DumpStatus }--dump-sourcewithout--headless→ parse error--dump-sourcewithout--url→ parse error--dump-source --dump-status→ parse error (conflicts)--url not-a-url→Mode::Guiwith URL parsing (may succeed as relative URL — decide behavior)--allow-httpflag is accepted and storedSmoke test (integration, in
crates/ie-shell/tests/)--headless --dump-status --url https://example.com, verify it exits with code 0 (placeholder output is fine)--headless, verify it exits with code 0Acceptance Criteria
cargo run -p ie-shell— window opens (existing behavior preserved)cargo run -p ie-shell -- --headless— runs and exits without opening a windowcargo run -p ie-shell -- --headless --dump-status --url https://example.com— exits cleanly with placeholder outputcargo test -p ie-shell— CLI parsing tests passcargo clippy -p ie-shell -- -D warnings— no warningscargo fmt -p ie-shell --check— formattedie-shellis noticeably faster after removing Phase 2 deps