- 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.