Constructor Pattern (RULE ZERO). Zero behaviour change, zero flag
drift — all original CLI flags preserved verbatim.
Before: install.sh — 1238 LOC monolith
After: install.sh — 138 LOC dispatcher (sources libs in order)
install/lib-*.sh — 16 cubes, max 183 LOC (lib-menu)
Cubes:
lib-log 21 LOC — logging primitives
lib-backup 63 LOC — rollback trap + BACKUP_PAIRS
lib-profile 115 LOC — MANIFEST.toml profile resolution
lib-args 92 LOC — CLI parsing + --help heredoc
lib-menu 183 LOC — whiptail/dialog/plain-text interactive picker
lib-plan 150 LOC — dry-run --no-execute output
lib-prereqs 91 LOC — hard + soft dependency checks
lib-primitives 131 LOC — primitive copy + MANIFEST drive
lib-rust 114 LOC — cargo workspace build + pre-built support
lib-scaffold 144 LOC — agent/skill/block scaffolding
lib-bridges 31 LOC — project-bridge install
lib-hooks 104 LOC — settings.json jq merge
lib-agents 77 LOC — assembled agent output
lib-skills 23 LOC — skill copy
lib-wizard 20 LOC — sleep-setup wizard invocation
lib-summary 59 LOC — post-install summary
Invariants preserved:
- macOS bash 3.2 compat (no associative arrays, no [[ ]], no ${,,})
- rollback trap wired via setup_backup_trap early in dispatcher
- jq-merge behaviour verbatim in lib-hooks
- scoped Cargo.toml regeneration in lib-rust
Function LOC limits: largest non-heredoc fn 22 LOC (check_soft_prereqs).
Three functions kept >30 LOC because heredoc-dominated (print_help,
print_summary, profile_members); splitting would fragment logical unit.
62 unique function names across cubes, zero duplicates (grep-verified).
bash -n passes on all 17 files. Runtime smoke test deferred to user's
shell (bash-readonly sandbox constraint).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
131 lines
4.3 KiB
Bash
131 lines
4.3 KiB
Bash
# shellcheck shell=bash
|
|
# lib-primitives.sh — shell-primitive copy + Rust workspace scoped build +
|
|
# .installed state helpers + --list printer.
|
|
#
|
|
# Requires: primitive_field from lib-profile.sh.
|
|
# Requires: say / warn / err from lib-log.sh.
|
|
# Reads globals: $AGENTS_DIR, $KIT_DIR, $INSTALLED_FILE, $MANIFEST.
|
|
|
|
# --- .installed state helpers --------------------------------------------
|
|
read_installed() {
|
|
[ -f "$INSTALLED_FILE" ] && cat "$INSTALLED_FILE" || true
|
|
}
|
|
|
|
write_installed() {
|
|
# stdin = newline-separated names; writes sorted-unique to INSTALLED_FILE.
|
|
mkdir -p "$(dirname "$INSTALLED_FILE")"
|
|
sort -u > "$INSTALLED_FILE"
|
|
}
|
|
|
|
# --- per-primitive install/remove ----------------------------------------
|
|
copy_shell_primitive() {
|
|
local name="$1" file src dst
|
|
file="$(primitive_field "$name" file)"
|
|
[ -n "$file" ] || { err "no 'file' for shell primitive $name"; return 1; }
|
|
src="$KIT_DIR/_primitives/$file"
|
|
dst="$AGENTS_DIR/_primitives/$file"
|
|
[ -f "$src" ] || { err "source missing: $src"; return 1; }
|
|
mkdir -p "$AGENTS_DIR/_primitives"
|
|
cp -f "$src" "$dst"
|
|
chmod +x "$dst"
|
|
say " + shell: $name ($file)"
|
|
}
|
|
|
|
remove_shell_primitive() {
|
|
local name="$1" file
|
|
file="$(primitive_field "$name" file)"
|
|
[ -n "$file" ] || return 0
|
|
rm -f "$AGENTS_DIR/_primitives/$file"
|
|
say " - shell: $name ($file)"
|
|
}
|
|
|
|
copy_rust_primitive() {
|
|
local name="$1" crate src dst_root dst
|
|
crate="$(primitive_field "$name" crate)"
|
|
[ -n "$crate" ] || { err "no 'crate' for rust primitive $name"; return 1; }
|
|
src="$KIT_DIR/_primitives/_rust/$crate"
|
|
[ -d "$src" ] || { err "source missing: $src"; return 1; }
|
|
dst_root="$AGENTS_DIR/_primitives/_rust"
|
|
dst="$dst_root/$crate"
|
|
mkdir -p "$dst/src"
|
|
cp -f "$src/Cargo.toml" "$dst/Cargo.toml"
|
|
[ -d "$src/src" ] && cp -rf "$src/src/"* "$dst/src/" 2>/dev/null || true
|
|
if [ -d "$src/tests" ]; then
|
|
mkdir -p "$dst/tests"
|
|
cp -rf "$src/tests/"* "$dst/tests/" 2>/dev/null || true
|
|
fi
|
|
say " + rust: $name (crate $crate)"
|
|
}
|
|
|
|
remove_rust_primitive() {
|
|
local name="$1" crate
|
|
crate="$(primitive_field "$name" crate)"
|
|
[ -n "$crate" ] || return 0
|
|
rm -rf "$AGENTS_DIR/_primitives/_rust/$crate"
|
|
say " - rust: $name (crate $crate)"
|
|
}
|
|
|
|
# --- rust enumeration / manifest / build all live in install/lib-rust.sh
|
|
# (Constructor-Pattern split — keeps this cube under 200 LOC).
|
|
|
|
# --- install / remove orchestrators --------------------------------------
|
|
# Install primitives from a name list (newline-separated on stdin).
|
|
install_primitives() {
|
|
local names existing combined kind p any_rust=0
|
|
names="$(cat)"
|
|
existing="$(read_installed)"
|
|
combined="$(printf '%s\n%s\n' "$existing" "$names" | grep -v '^$' || true)"
|
|
while IFS= read -r p; do
|
|
[ -z "$p" ] && continue
|
|
kind="$(primitive_field "$p" kind)"
|
|
case "$kind" in
|
|
shell) copy_shell_primitive "$p" ;;
|
|
rust) copy_rust_primitive "$p"; any_rust=1 ;;
|
|
*) warn "unknown primitive: $p (skipping)"; continue ;;
|
|
esac
|
|
done <<< "$names"
|
|
printf '%s\n' "$combined" | write_installed
|
|
if [ "$any_rust" = "1" ]; then
|
|
regenerate_rust_workspace
|
|
fi
|
|
}
|
|
|
|
# Remove a single primitive by name.
|
|
remove_primitive() {
|
|
local name="$1" kind existing
|
|
kind="$(primitive_field "$name" kind)"
|
|
case "$kind" in
|
|
shell) remove_shell_primitive "$name" ;;
|
|
rust) remove_rust_primitive "$name" ;;
|
|
*) err "unknown primitive: $name"; return 1 ;;
|
|
esac
|
|
existing="$(read_installed)"
|
|
printf '%s\n' "$existing" | grep -vFx "$name" | grep -v '^$' | write_installed || true
|
|
if [ "$kind" = "rust" ]; then
|
|
regenerate_rust_workspace
|
|
fi
|
|
}
|
|
|
|
# --- --list implementation -----------------------------------------------
|
|
cmd_list() {
|
|
echo
|
|
printf '%-22s %-6s %-10s %s\n' "NAME" "KIND" "STATUS" "DESCRIPTION"
|
|
printf '%-22s %-6s %-10s %s\n' "----" "----" "------" "-----------"
|
|
local installed name kind desc status count
|
|
installed="$(read_installed)"
|
|
while IFS= read -r name; do
|
|
[ -z "$name" ] && continue
|
|
kind="$(primitive_field "$name" kind)"
|
|
desc="$(primitive_field "$name" desc)"
|
|
if printf '%s\n' "$installed" | grep -qFx "$name"; then
|
|
status="INSTALLED"
|
|
else
|
|
status="-"
|
|
fi
|
|
printf '%-22s %-6s %-10s %s\n' "$name" "$kind" "$status" "$desc"
|
|
done < <(all_primitive_names)
|
|
echo
|
|
count="$(printf '%s\n' "$installed" | grep -c . || true)"
|
|
printf '%s primitives installed (state: %s)\n' "${count:-0}" "$INSTALLED_FILE"
|
|
echo
|
|
}
|