yog 0.0.1

yog: a balls-oriented session manager for lernie loops (egui frontend)
Documentation
//! Firing the composer's start (DESIGN §3.4, §8.1): resolve the bare / path rung
//! [`StartInputs`], run [`start::prepare`], then the detached prompt. Split from
//! [`super::input_bar`] per §12's 300-line budget. Coverage-excluded shell glue —
//! every decision lives in the tested `start`/`AppModel` modules; this only wires
//! the composer's Enter to them and folds the outcome into the banner (§7.3).

use crate::AppModel;
use crate::actions::ActionsState;
use crate::cli_outbound::Cli;
use crate::names::SplitMix64;
use crate::start::{self, Deps, StartInputs};
use std::path::Path;

/// Fire the composer's start (§3.4): the **path** rung when a work directory is
/// drafted (`actions.path_dir`), else the **bare** rung. Returns whether the
/// prompt launched, so the draft clears only on a clean send (RAM until sent,
/// §5.3).
pub(super) fn fire_start(
    model: &mut AppModel,
    actions: &mut ActionsState,
    lernie: &Cli,
    bl: &Cli,
    mint_seed: u64,
    text: &str,
) -> bool {
    let dir = actions.path_dir.trim().to_owned();
    let inputs = if dir.is_empty() {
        model.start_bare_inputs()
    } else {
        model.start_path_inputs(Path::new(&dir))
    };
    fire_inputs(model, actions, lernie, bl, inputs, mint_seed, text)
}

/// Fire the bare rung (§3.4) — the empty-world bootstrap composer's Enter.
/// `pub(super)`: workspace.rs's placeholder reuses it (bare only, no path field).
pub(super) fn fire_bare(
    model: &mut AppModel,
    actions: &mut ActionsState,
    lernie: &Cli,
    bl: &Cli,
    mint_seed: u64,
    text: &str,
) -> bool {
    let inputs = model.start_bare_inputs();
    fire_inputs(model, actions, lernie, bl, inputs, mint_seed, text)
}

/// Run `prepare` (mint + `lernie new` when the world has no workspace, else
/// idempotent skips) then the detached prompt with the typed text, for an already
/// resolved [`StartInputs`]. The whole flow rides the one planner; a failure rode
/// its own ops line (§8.1), read back into the banner either way (§7.3).
fn fire_inputs(
    model: &mut AppModel,
    actions: &mut ActionsState,
    lernie: &Cli,
    bl: &Cli,
    inputs: StartInputs,
    mint_seed: u64,
    text: &str,
) -> bool {
    let mut rng = SplitMix64::from_seed(mint_seed);
    let deps = Deps {
        bl: bl.clone(),
        lernie: lernie.clone(),
        state_root: model.state_root().to_path_buf(),
        gate: model.toolchain().clone(),
    };
    let launched = match start::prepare(&deps, &inputs, &mut rng, &super::now_ts()) {
        Ok(p) => start::execute_prompt(
            lernie,
            model.state_root(),
            &super::now_ts(),
            &p.name,
            &p.cwd,
            &p.workspace,
            text,
        )
        .is_ok(),
        Err(_) => false,
    };
    model.after_lernie_verb();
    actions.last_failure = model.last_failure();
    launched
}