Creates tests/e2e/smoketest.sh — a hermetic end-to-end test that:
- Sets up a mock ZUUR (python3 http.server serving local index/recipes)
- Creates fake zeta-makepkg and zeta scripts (no real Lua tools needed)
- Tests the full pipeline: search → install → upgrade → info → remove
- Verifies exit codes (0, 2 for not-found)
- Verifies installed.json state tracking
- Verifies binary installation/removal via ZETA_ROOT
BUG FOUND (documented in problems.md, not fixed):
- info.d scanDepsArray stores ptrdiff_t indexOf() result in size_t,
causing ArrayIndexError when recipe lacks a deps field.
Workaround: recipe includes deps = {}.
Evidence: .omo/evidence/task-27-tofu-core.log — 16/16 checks pass.
- Add runRemove() to tofu.install (zeta subprocess module)
- Same pipeProcess/tee/rolling-buffer pattern as runLocalProvide
- Uses -Remove instead of -LocalProvide
- Appends --force flag when force=true
- Create tofu.commands.remove with removeCommand()
- Checks tofu-installed via state.d (warns if not, still proceeds)
- Confirm prompt (Remove <name>? [y/N]) unless --noconfirm
- Detects 'still required by' in zeta error → suggests --force
- Cleans up install record on success
- Wire remove case in main.d dispatch
- 6 unittests with fake zeta scripts
Add buildAll() to src/tofu/build.d — sequential builder with:
- Empty plan → 'nothing to build' no-op
- Recipe existence pre-check → fail-fast on missing
- Skip-if-exists: don't rebuild when output present (unless --force)
- Separator line: U+2500 box chars '──── building <name> (i/n) ────'
- Fail-fast: halt immediately on first BuildException
6 unittests: all succeed, first fails, empty plan, skip existing,
force rebuild, missing recipe.
- Add tofu.build module with runMakepkg() public API
- BuildException for missing binary, non-zero exit, missing output
- Real-time stdout/stderr streaming with last-20-lines stderr capture
- Conditional --force flag based on force parameter
- zetaToolchainPath resolution from Config
- 7 unittests using fake zeta-makepkg shell scripts
- pipeProcess + Redirect.stderr for tee approach
Port of ZETA lib/deps.lua depth-first resolution algorithm:
- DepNode/DepTree structs for topologically-ordered dependency trees
- resolveDepTree() with function-pointer seam for testability
- Cycle detection with full chain message (e.g. 'A -> B -> A')
- Memoization to skip already-resolved nodes
- Parses recipe.deps string[] into DepConstraint[] via DepConstraint.parse
7 unittests: constraint parsing, linear chain, self-cycle, mutual
cycle, missing dep propagation, diamond shared dep, leaf node.