FILESpawn/FILESpawnFds/FILEReap
A JABC script cannot run a child process: the C leaves exist but aren't bound. Bind them, plus an "output as a Buf" convenience via a file + mmap sink — the deadlock-free, zero-copy path. Method: Issues.
io.spawn/reap are shown in js/API.md but NOT bound (grep js/ for
spawn/Spawn → none). The leaves exist: abc/FILE.h:537 FILESpawn (pipes for stdin/stdout, *stderr inherited*), :545 FILESpawnFds (caller fds, -1=inherit), :552 FILEReap (FILESIGNAL on signal death).
child and read its output. Naive pipe-drain *deadlocks* at the 64 KB pipe buffer, and a fixed-cap Buf overflows — the binding must dodge both.
memfd/O_TMPFILE absent from FILE.h); the
zero-copy sink uses a named temp file via FILECreate + FILEMapRO.
io.spawn(path, argv) → {pid, stdin, stdout} (fds); `io.spawnFds(path,
argv, inFd, outFd) → pid (-1 inherits); io.reap(pid) → {code, signal}`.
Buf": spawn with a file sink, reap, mmap → the child's
stdout as a zero-copy Buf (no pipe, no deadlock, no drain loop).
array → u8css; fds + pid cross as numbers; no held JS refs (rule #4).
io.open/spawnFds/
reap/mmap) — a JS-side helper, no C format logic.
{code}; FILESIGNAL → {signal} (exactlyone set). Caller owns + closes every fd; the binding never reaps on GC.
io.exec/io.capture
(file-sink → mmap) returning {out: Buf, code}, optional {stdin: Buf}.
io.memfd() anon sink (needs a new
FILEMemFd abc leaf); *stderr capture* (FILESpawn inherits it — needs a stderr-fd spawn variant or a self-made pipe); an async streaming child module over pol (mirror net.cpp): two-pipe poll-drain (no deadlock) + SIGCHLD/waitpid reaping + .on('data'|'exit').
io.spawn("/bin/echo",["echo","hi"]) → read stdout == "hi\n",
io.reap → {code:0}; a non-zero exit and a signal death both surface correctly; the file-sink io.exec returns the output Buf.
mmap convenience.js/API.md; update
js/INDEX.md (io.cpp section).
memfd are flagged follow-ups that may
need small new abc leaves; the async child module is a larger follow-up.
0155ee76 (2026-06-21): io.spawn(path,argv) → {pid,stdin,stdout},
io.spawnFds(path,argv,inFd,outFd) → pid (-1=inherit), io.reap(pid) → {code}|{signal} — pure marshalling over FILESpawn/FILESpawnFds/ FILEReap; plus io.unlink (FILEUnLink). argv→u8css idiom from WIRECLI.c. Tests red→green (echo, stdin round-trip, exit-code, signal, spawnFds-inherit, argv-throws); ctest -R JABC 18/18, ASAN/LSan clean.
io.exec (file-sink→mmap) was built then CUT on review: the name
mismatches POSIX/Node exec and it was sugar over spawn. Capture-stdout recipes (pipe-drain + zero-copy file+mmap) stay in API.md over the leaves.
memfd anon sink, an async pol-driven child
module, {stdin:Buf} — and a Buf.close() doc/impl gap spotted in API.md.