System directories (#635)

Private native: the OS temp dir, "" only where there is no filesystem.

pub fn temp_dir() -> text?env#read

Returns the system temporary directory, or null on a target with no filesystem (the browser). Prefer this over reading TMPDIR / TEMP / TMP directly: those differ by platform (Unix uses TMPDIR, Windows TEMP/TMP) and this also applies the OS fallback (e.g. /tmp) when none is set.

pub fn cache_dir() -> text?env#read

Returns loft's per-user cache directory ($XDG_CACHE_HOME/loft, else $HOME/.cache/loft) — the same root the engine caches into — or null on a target with no filesystem (the browser).

pub fn host_input(wait_ms: integer = -1) -> text

Reads pending host input as one text; empty when there is none. The source is per-target: stdin on native and --native-wasm (WASI); the JS host's input QUEUE on --html — seed it with globalThis.loftInput before loft_start, and push live messages any time with globalThis.loftPush(msg) (e.g. fetch() completions). Use for a headless compute module or a polled input loop — the inbound mirror of host_output. The engine only moves opaque bytes; the program parses them.

wait_ms says how long to wait for input that has not arrived yet. The default -1 reads the WHOLE stream, waiting for stdin to end; 0 takes what is already there and returns at once; a positive value waits that many milliseconds for the first byte. Ask with a bound whenever the answer might be that nobody is listening: an absent host never closes stdin, so the default form waits forever for a reply that is not coming.

host_output("MODE?"); mode = host_input(200); // "" => no host, run locally

On --html every read already polls (a page cannot wait for a message its own thread has to deliver), and on --native-wasm, which has no threads, a bounded read falls back to waiting for the whole stream.

pub fn host_output(msg: text)

Sends one STRUCTURED message to the host shell — the outbound mirror of host_input, distinct from user-facing print. Per target: a line on stderr (native and WASI — the invoking process can script it); the page's globalThis.loftOutput(msg) handler on --html. The browser pattern for loft-initiated work: host_output a request (e.g. "fetch <url>"), the JS shell acts on it, and pushes the completion back via loftPush for host_input to pop — JS owns the network, loft stays pure compute.