#!/bin/sh -u
# dtr - ports manager

readonly PROG_NAME="${0##*/}"
readonly PROG_VERSION="1.2.1"

SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
LOCAL_BUILD_DIR="$SCRIPT_DIR/build"
LOCAL_DTR_CACHE="$LOCAL_BUILD_DIR/cache/dtr"
LOCAL_DTR_DISTDIR="$LOCAL_DTR_CACHE/distfiles"
LOCAL_DTR_WORK="$LOCAL_BUILD_DIR/dtr-work"
LOCAL_DTR_TMP="$LOCAL_BUILD_DIR/tmp"

: "${DTR_DIR:=$SCRIPT_DIR/ports}"
: "${DTR_VERBOSITY:=1}"
: "${DTR_MAKE:=dmake.sh}"
: "${DTR_NEW_MAKE:=ndmake.sh}"
: "${DTR_SKIP_CONFIRM:=0}"
: "${DTR_REMOTE:=origin}"
: "${DTR_BRANCH:=main}"
: "${DTR_CACHE:=$LOCAL_DTR_CACHE}"
: "${DISTDIR:=$LOCAL_DTR_DISTDIR}"
: "${SPC_EXT:=tzst}"
: "${BUILDBASE:=$LOCAL_DTR_WORK}"
: "${TMPDIR:=$LOCAL_DTR_TMP}"
: "${DTR_SPC_BIN:=}"
: "${DTR_ROOTFS:=/}"
: "${DTR_TARGET:=}"
: "${DTR_LIBC:=}"
: "${DTR_SYSROOT:=}"
: "${NO_COLOR:=}"

readonly DEFAULT_REPO="https://codeberg.org/derivelinux/ports"
readonly EXTENSION_DIRS="/share/dtr /usr/share/dtr"

# === FORMAT STRINGS ===
# highlight:
readonly _str_highlight_o="<ul><bold>"
readonly _str_highlight_c="</ul></bold>"
readonly _str_highlight_f="${_str_highlight_o}%s${_str_highlight_c}"

# === LOGGING ===
strip_tags() { printf "$@" | sed 's/<[^>]*>//g'; }

log_printf="strip_tags"
if [ -z "$NO_COLOR" ] && _cmd="$(command -v tmlf 2>/dev/null)"; then
    log_printf="$_cmd"
fi

msg() {
    [ "$DTR_VERBOSITY" -lt 1 ] && return
    $log_printf '<green>==></green> %s\n' "$*" >&2
}
info() {
    [ "$DTR_VERBOSITY" -lt 1 ] && return
    $log_printf '<dim>)</dim>    %s\n' "$*" >&2
}
die() { $log_printf '%s: <bg-red>error</bg-red>: %s\n' "$PROG_NAME" "$*" >&2; exit 1; }
warn() { $log_printf '%s: <bg-yellow>warning</bg-yellow>: %s\n' "$PROG_NAME" "$*" >&2; }

# === UTILITIES ===
chill() { head -n 32 "$1" | tail -n 31 | sed 's/^#//'; }
confirm_action() {
    [ "$DTR_SKIP_CONFIRM" -eq 1 ] && return 0
    [ -t 0 ] && [ -t 1 ] || return 1
    $log_printf '%s [y/N] ' "$1"
    read -r ans </dev/tty
    case "$ans" in [Yy]*) return 0 ;; *) return 1 ;; esac
}
for_each_line() {
    while IFS= read -r line; do
        [ -n "$line" ] || continue
        "$@" "$line"
    done
}
tmp_file() { printf '%s/dtr-%s-%s' "$TMPDIR" "$1" "$$"; }
strip_md_link() { printf '%s' "$1" | sed 's/\[\([^]]*\)\]([^)]*)/\1/g'; }

resolve_spc_bin() {
    if [ -n "$DTR_SPC_BIN" ]; then
        [ -x "$DTR_SPC_BIN" ] || die "spc binary not executable: $DTR_SPC_BIN"
        printf '%s\n' "$DTR_SPC_BIN"
        return 0
    fi
    if [ -x "$SCRIPT_DIR/bs-spc" ]; then
        printf '%s\n' "$SCRIPT_DIR/bs-spc"
        return 0
    fi
    if [ -x "$SCRIPT_DIR/spc" ]; then
        printf '%s\n' "$SCRIPT_DIR/spc"
        return 0
    fi
    command -v spc >/dev/null 2>&1 || die "spc not found (set DTR_SPC_BIN or keep bs-spc beside dtr)"
    command -v spc
}

spc_cmd() {
    _spc_bin="$(resolve_spc_bin)"
    _spc_root="${DTR_ROOTFS%/}"
    [ -n "$_spc_root" ] || _spc_root="/"
    _spc_db="${SPC_DB:-$_spc_root/var/lib/spc/installed}"
    _spc_lock="${SPC_LOCK:-$_spc_root/var/lib/spc/lock}"
    SPC_ROOT="$_spc_root" \
    SPC_DB="$_spc_db" \
    SPC_LOCK="$_spc_lock" \
    SPC_PORTS="$DTR_DIR" \
    SPC_TARGET="$DTR_TARGET" \
    SPC_LIBC="$DTR_LIBC" \
    SPC_SYSROOT="$DTR_SYSROOT" \
        "$_spc_bin" "$@"
}

setup_cross_env() {
    _target="${DTR_TARGET:-}"
    _sysroot="${DTR_SYSROOT:-}"
    _cc=""
    _cxx=""
    _ar=""
    _ranlib=""
    _strip=""
    _target_flag=""
    _sysroot_flag=""
    _have_prefixed_binutils=0

    if [ -n "$_target" ]; then
        _target_flag="--target=$_target"

        if command -v "${_target}-ar" >/dev/null 2>&1; then
            _ar="${_target}-ar"
            _have_prefixed_binutils=1
        elif command -v llvm-ar >/dev/null 2>&1; then
            _ar="llvm-ar"
        elif command -v ar >/dev/null 2>&1; then
            _ar="ar"
        fi

        if command -v "${_target}-ranlib" >/dev/null 2>&1; then
            _ranlib="${_target}-ranlib"
            _have_prefixed_binutils=1
        elif command -v llvm-ranlib >/dev/null 2>&1; then
            _ranlib="llvm-ranlib"
        elif command -v ranlib >/dev/null 2>&1; then
            _ranlib="ranlib"
        fi

        if command -v "${_target}-strip" >/dev/null 2>&1; then
            _strip="${_target}-strip"
            _have_prefixed_binutils=1
        elif command -v llvm-strip >/dev/null 2>&1; then
            _strip="llvm-strip"
        elif command -v strip >/dev/null 2>&1; then
            _strip="strip"
        fi

        # Some ports derive AR/RANLIB from CROSS_COMPILE; only export it when
        # target-prefixed binutils actually exist.
        if [ "$_have_prefixed_binutils" -eq 1 ]; then
            export CROSS_COMPILE="${_target}-"
        else
            unset CROSS_COMPILE 2>/dev/null || true
        fi
    fi

    # Always force clang-based toolchain for package builds.
    command -v clang >/dev/null 2>&1 || die "clang not found in PATH"
    command -v clang++ >/dev/null 2>&1 || die "clang++ not found in PATH"

    # Capture absolute paths to clang/clang++ for wrappers
    _clang_path="$(command -v clang)"
    _clangxx_path="$(command -v clang++)"

    _ccwrap_dir="${TMPDIR%/}/dtr-ccwrap.$$"
    mkdir -p "$_ccwrap_dir" || die "failed to create wrapper dir: $_ccwrap_dir"

    _cc="$_ccwrap_dir/cc"
    cat > "$_cc" <<EOF
#!/bin/sh
set -- -static "\$@"
[ -n "$_target" ] && set -- "--target=$_target" "\$@"
[ -n "$_sysroot" ] && set -- "--sysroot=$_sysroot" "\$@"
exec "$_clang_path" "\$@"
EOF
    chmod +x "$_cc" || die "failed to chmod wrapper: $_cc"

    _cxx="$_ccwrap_dir/cxx"
    cat > "$_cxx" <<EOF
#!/bin/sh
set -- -static "\$@"
[ -n "$_target" ] && set -- "--target=$_target" "\$@"
[ -n "$_sysroot" ] && set -- "--sysroot=$_sysroot" "\$@"
exec "$_clangxx_path" "\$@"
EOF
    chmod +x "$_cxx" || die "failed to chmod wrapper: $_cxx"

    if [ -n "$_sysroot" ]; then
        _sysroot_flag="--sysroot=$_sysroot"
        export PKG_CONFIG_SYSROOT_DIR="$_sysroot"
        export PKG_CONFIG_LIBDIR="$_sysroot/usr/lib/pkgconfig:$_sysroot/usr/share/pkgconfig:$_sysroot/lib/pkgconfig"
    fi

    export CC="$_cc"
    export CXX="$_cxx"
    [ -n "$_ar" ] && export AR="${AR:-$_ar}"
    [ -n "$_ranlib" ] && export RANLIB="${RANLIB:-$_ranlib}"
    [ -n "$_strip" ] && export STRIP="${STRIP:-$_strip}"

    _libc_note=""
    [ -n "$DTR_LIBC" ] && _libc_note="-D_DERIVE_LIBC_${DTR_LIBC}=1"

    export CFLAGS="${CFLAGS:-} $_libc_note"
    export CXXFLAGS="${CXXFLAGS:-} $_libc_note"
    export LDFLAGS="${LDFLAGS:-} -static"
}

# === STRACE PARSING (LEGACY SUPPORT) ===
parse_strace() {
    awk '
        / = -1 / {next}
        function extract_path(line) {
            start = index(line, "<")
            if (start == 0) return ""
            rest = substr(line, start + 1)
            end = index(rest, ">")
            if (end == 0) return ""
            return substr(rest, 1, end - 1)
        }
        /(open|openat|creat)\(.*(O_CREAT|O_WRONLY)/ ||
         /(rename|renameat|renameat2|symlink|symlinkat|link|linkat)/ {
            if ($0 ~ /= [0-9]+</) {
                path = extract_path($0)
                # Only track typical system paths to avoid noise
                if (path ~ /^\/(usr|etc|lib|bin|var|opt|sbin)/) print path
            }
        }
    ' "$1" | sort -u
}

# === PACKAGE DISCOVERY ===
find_package() {
    local res
    case "$1" in
        /*)
            if [ -d "$1" ] && [ -f "$1/$DTR_NEW_MAKE" ]; then
                printf '%s' "$1"
                return 0
            fi
            return 1
            ;;
        *)
            res=$(find "$DTR_DIR" -mindepth 2 -maxdepth 2 -type d -name "$1" -print -quit 2>/dev/null)
            if [ -n "$res" ] && [ -f "$res/$DTR_NEW_MAKE" ]; then
                printf '%s' "$res"
                return 0
            fi
            return 1
            ;;
    esac
}

get_makefile() {
    local dir="$1"
    if [ -f "$dir/$DTR_NEW_MAKE" ]; then
        echo "$dir/$DTR_NEW_MAKE"
    else
        return 1
    fi
}

resolve_package_arg() {
    case "$1" in
        /*) printf '%s' "$1"; return ;;
    esac

    local found
    found=$(find_package "$1")
    if [ -n "$found" ]; then
        printf '%s' "$found"
        return
    fi

    if [ -d "$1" ]; then
        cd "$1" && pwd
        return
    fi

    printf '%s' "$1"
}

# Check installed status via spc
is_installed() {
    spc_cmd info "$1" >/dev/null 2>&1
}

# === METADATA ===
get_package_version() {
    local dir makefile
    dir=$(find_package "$1") || return 1
    makefile=$(get_makefile "$dir") || return 1
    grep '^VERSION=' "$makefile" 2>/dev/null |
        head -n1 | cut -d= -f2- | tr -d '"'
}
get_package_release() {
    local dir makefile
    dir=$(find_package "$1") || return 1
    makefile=$(get_makefile "$dir") || return 1
    local rel
    rel=$(grep '^RELEASE=' "$makefile" 2>/dev/null |
        head -n1 | cut -d= -f2- | tr -d '"')
    echo "${rel:-1}"
}
# Extract NAME explicitly, falling back to empty if not found
get_package_name_var() {
    local dir makefile
    dir=$(find_package "$1") || return 1
    makefile=$(get_makefile "$dir") || return 1
    grep '^NAME=' "$makefile" 2>/dev/null |
        head -n1 | cut -d= -f2- | tr -d '"'
}
get_package_commit() {
    local dir repo makefile
    dir=$(find_package "$1") || return 1
    makefile=$(get_makefile "$dir") || return 1
    repo=$(grep '^REPO=' "$makefile" 2>/dev/null |
           head -n1 | cut -d= -f2- | tr -d '"')
    [ -n "$repo" ] || return 1
    git ls-remote --quiet "$repo" HEAD 2>/dev/null | cut -f1
}
get_package_source() {
    local dir makefile
    dir=$(find_package "$1") || return 1
    makefile=$(get_makefile "$dir") || return 1
    awk '
        /^SOURCE=/{
            line=substr($0, index($0,"=")+1)
            while (line ~ /\\$/) {
                sub(/\\$/, "", line)
                if (getline > 0) {
                    sub(/^[ \t]*/, "", $0)
                    line=line $0
                } else {
                    break
                }
            }
            sub(/^"/, "", line)
            sub(/"$/, "", line)
            print line
            exit
        }
    ' "$makefile"
}
get_package_git_url() {
    local src tok
    src=$(get_package_source "$1") || return 1
    for tok in $src; do
        tok="${tok%%::*}"
        case "$tok" in
            *git@*:*|git://*|*://*.git|*://*/.git)
                printf '%s\n' "$tok"
                return 0
                ;;
        esac
    done
    return 1
}
resolve_git_version() {
    local ver repo commit
    ver="$1"
    case "$ver" in
        git:*) printf '%s\n' "$ver"; return 0 ;;
        git)
            repo=$(get_package_git_url "$2" || true)
            if [ -n "$repo" ]; then
                commit=$(git ls-remote --quiet "$repo" HEAD 2>/dev/null | cut -f1)
                [ -n "$commit" ] && { printf 'git:%s\n' "$commit"; return 0; }
            fi
            ;;
    esac
    printf '%s\n' "$ver"
}
get_info_field() {
    local infofile="$1" field="$2"
    [ -f "$infofile" ] || return 1
    grep "^${field}:" "$infofile" | head -n1 | cut -d: -f2- | sed 's/^ *//'
}
format_package_info() {
    local pkg="$1" fmt="$2"
    local dir infofile name="" desc="" maint="" ver="" contributors=""

    dir=$(find_package "$pkg")
    if [ -n "$dir" ]; then
        infofile="$dir/info"
        ver=$(get_package_version "$pkg")
        ver=$(resolve_git_version "$ver" "$pkg")

        if [ -f "$infofile" ]; then
            name=$(get_info_field "$infofile" "name")
            desc=$(get_info_field "$infofile" "description")
            maint=$(get_info_field "$infofile" "maintainer")
            contributors=$(get_info_field "$infofile" "contributors")

            [ -n "$maint" ] && maint=$(strip_md_link "$maint")
            [ -n "$contributors" ] && contributors=$(strip_md_link "$contributors")
        fi
    fi

    [ -n "$ver" ] && ver="+$ver"
    [ -n "$maint" ] && maint=":$maint"
    [ -n "$desc" ] && desc=" - $desc"

    eval "echo $fmt"
}

# === DEPENDENCIES ===
parse_dep_name() {
    case "$1" in
        [/.]*)  printf '%s' "${1#?}" ;;
        \>*)    printf '%s' "${1#?}" ;;
        *)      printf '%s' "$1" ;;
    esac
}
parse_dep_type() {
    case "$1" in
        /*)  printf 'link' ;;
        \>*) printf 'runtime' ;;
        .*)  printf 'build' ;;
        *)   printf 'link' ;;
    esac
}
read_deps_file() {
    local depsfile="$1"
    [ -f "$depsfile" ] || return

    while IFS= read -r dep; do
        case "$dep" in ''|\#*) continue ;; esac
        printf '%s\n' "$dep"
    done < "$depsfile"
}

# VISUALIZATION
print_dep_tree() {
    local pkg="$1"
    local prefix="${2:-}"
    local is_last="${3:-1}" # 1 = yes, 0 = no
    local visited_file="${4:-}"
    
    # Setup visited tracking
    local is_toplevel=0
    if [ -z "$visited_file" ]; then
        visited_file=$(tmp_file "tree-visited")
        > "$visited_file"
        is_toplevel=1
        $log_printf "<bold>%s</bold>\n" "$pkg"
    fi

    local dir depsfile
    dir=$(find_package "$pkg") || return
    depsfile="$dir/deps"
    [ -f "$depsfile" ] || return

    # Load deps into array for processing
    local deps_list=""
    while IFS= read -r line; do
        [ -n "$line" ] || continue
        case "$line" in \#*) continue ;; esac
        deps_list="$deps_list $line"
    done < "$depsfile"

    # Process deps
    local count=0
    local total
    total=$(echo "$deps_list" | wc -w)
    
    for raw_dep in $deps_list; do
        count=$((count + 1))
        local d_name d_type d_status connector
        
        d_name=$(parse_dep_name "$raw_dep")
        d_type=$(parse_dep_type "$raw_dep")
        
        # Determine connector style
        if [ "$count" -eq "$total" ]; then
            connector="└─"
            new_prefix="${prefix}   "
            d_last=1
        else
            connector="├─"
            new_prefix="${prefix}│  "
            d_last=0
        fi

        # Determine status
        if grep -qxF "$d_name" "$visited_file"; then
            d_status=" <dim>(...)</dim>"
            recurse=0
        else
            echo "$d_name" >> "$visited_file"
            if is_installed "$d_name"; then
                d_status=" <green>[installed]</green>"
            else
                d_status=" <yellow>[new]</yellow>"
            fi
            recurse=1
        fi
        
        # Type indicator
        local t_mk=""
        case "$d_type" in
            link)    t_mk=" <dim>[link-time]</dim>" ;; 
            runtime) t_mk=" <dim>[runtime]</dim>" ;;
            build)   t_mk=" <dim>[build-time]</dim>" ;;
        esac

        $log_printf "%s%s <bold>%s</bold>%s%s\n" "$prefix" "$connector" "$d_name" "$t_mk" "$d_status"

        if [ "$recurse" -eq 1 ]; then
             print_dep_tree "$d_name" "$new_prefix" "$d_last" "$visited_file"
        fi
    done

    [ "$is_toplevel" -eq 1 ] && rm -f "$visited_file"
}

build_ordered_deps() {
    local target="$1" seen order
    seen=$(tmp_file "seen")
    order=$(tmp_file "order")

    > "$seen"
    > "$order"
    _build_deps_recursive "$target" "$seen" "$order"
    cat "$order"
    rm -f "$seen" "$order"
}
_build_deps_recursive() {
    local target="$1" seen="$2" order="$3" dir depsfile dep name

    grep -qxF "$target" "$seen" 2>/dev/null && return
    printf '%s\n' "$target" >> "$seen"

    dir=$(find_package "$target") || return 0
    depsfile="$dir/deps"

    read_deps_file "$depsfile" | while IFS= read -r dep; do
        name=$(parse_dep_name "$dep")
        _build_deps_recursive "$name" "$seen" "$order"
    done

    # Add to build order if NOT installed
    is_installed "$target" || printf '%s\n' "$target" >> "$order"
}
find_reverse_deps() {
    local target="$1" filter_type="${2:-}" pkg pkgdir depsfile dep name type

    # Use spc to list all installed packages
    spc_cmd list | cut -d'+' -f1 | while IFS= read -r pkg; do
        pkgdir=$(find_package "$pkg") || continue
        depsfile="$pkgdir/deps"

        read_deps_file "$depsfile" | while IFS= read -r dep; do
            name=$(parse_dep_name "$dep")
            [ "$name" = "$target" ] || continue

            if [ -n "$filter_type" ]; then
                type=$(parse_dep_type "$dep")
                [ "$type" = "$filter_type" ] || continue
            fi

            printf '%s\n' "$pkg"
            break
        done
    done
}
rebuild_dependents() {
    local target="$1" filter_type="${2:-}" rebuilt countf is_toplevel=0
    rebuilt=$(tmp_file "rebuilt")
    countf=$(tmp_file "count")

    [ -f "$rebuilt" ] || { > "$rebuilt"; echo 0 > "$countf"; is_toplevel=1; }
    grep -qxF "$target" "$rebuilt" && { cat "$countf" 2>/dev/null || echo 0; return; }

    printf '%s\n' "$target" >> "$rebuilt"

    find_reverse_deps "$target" "$filter_type" | while IFS= read -r dep; do
        [ -n "$dep" ] || continue

        msg "rebuilding dependent: $dep"

        # Rebuild using standard workflow
        do_make "$dep" >/dev/null
        install_package "$dep" >/dev/null

        local count
        count=$(cat "$countf")
        count=$((count + 1))
        echo "$count" > "$countf"

        rebuild_dependents "$dep" "$filter_type" >/dev/null
    done

    cat "$countf" 2>/dev/null || echo 0
    [ "$is_toplevel" -eq 1 ] && rm -f "$rebuilt" "$countf"
}

# === BUILD & INSTALL ===
build_package() {
    local pkg="$1" dir makefile

    [ -z "$pkg" ] && die "build_package called with empty package name"

    dir=$(find_package "$pkg") || die "package $pkg not found"
    makefile=$(get_makefile "$dir") || die "no build script found for $pkg"

    # CACHE INVALIDATION
    # If we are building, we must invalidate the cache to prevent 'install'
    # from picking up the old package instead of the new build artifacts.
    local pkgname ver rel pkg_archive
    pkgname=$(get_package_name_var "$pkg")
    [ -z "$pkgname" ] && pkgname="${dir##*/}"
    ver=$(get_package_version "$pkg")
    ver=$(resolve_git_version "$ver" "$pkg")
    rel=$(get_package_release "$pkg")

    if [ -n "$ver" ]; then
        pkg_archive="${DTR_CACHE}/${pkgname}+${ver}-${rel}.spc.${SPC_EXT}"
        if [ -f "$pkg_archive" ]; then
            rm -f "$pkg_archive"
            info "invalidated cache for $pkgname"
        fi
    fi

    msg "building $pkg"
    cd "$dir" || die "cannot cd to $dir"
    DISTDIR="$DISTDIR" \
    BUILDBASE="$BUILDBASE" \
    TMPDIR="$TMPDIR" \
    sh "$makefile" make || die "make failed for $pkg"
}

check_cache_validity() {
    local pkg="$1" cache_file="$2"
    [ -f "$cache_file" ] || return 1
    
    local dir depsfile
    dir=$(find_package "$pkg") || return 0
    depsfile="$dir/deps"
    [ -f "$depsfile" ] || return 0

    local cache_mtime
    cache_mtime=$(stat -c %Y "$cache_file")

    # Check link-time dependencies
    while IFS= read -r line; do
        [ -z "$line" ] && continue
        case "$line" in \#*) continue ;; esac
        
        local type name
        type=$(parse_dep_type "$line")
        name=$(parse_dep_name "$line")

        # Only care about link-time deps (default or /)
        if [ "$type" = "link" ]; then
            # Check installed lockfile timestamp
            local lockroot="${DTR_ROOTFS%/}"
            [ -n "$lockroot" ] || lockroot="/"
            local lockfile="${lockroot}/var/lib/spc/lock/${name}.lock"
            if [ -f "$lockfile" ]; then
                local lock_mtime
                lock_mtime=$(stat -c %Y "$lockfile")
                if [ "$lock_mtime" -gt "$cache_mtime" ]; then
                    info "cache invalid: dependency $name is newer than cached $pkg"
                    return 1
                fi
            fi
        fi
    done < "$depsfile"
    return 0
}

install_package() {
    local pkg="$1" dir makefile pkgname ver_raw ver rel staging_dir pkg_archive is_legacy=0

    dir=$(find_package "$pkg") || die "package $pkg not found"
    makefile=$(get_makefile "$dir") || die "no build script found for $pkg"

    if [ "${makefile##*/}" = "$DTR_MAKE" ]; then
        is_legacy=1
    fi

    pkgname=$(get_package_name_var "$pkg")
    [ -z "$pkgname" ] && pkgname="${dir##*/}"

    ver_raw=$(get_package_version "$pkg")
    ver=$(resolve_git_version "$ver_raw" "$pkg")
    rel=$(get_package_release "$pkg")
    [ -z "$ver_raw" ] && die "cannot determine version for $pkg"

    pkg_archive="${DTR_CACHE}/${pkgname}+${ver}-${rel}.spc.${SPC_EXT}"

    # CACHE CHECK
    if [ -f "$pkg_archive" ]; then
        if check_cache_validity "$pkgname" "$pkg_archive"; then
            msg "using cached package: $pkg_archive"
            msg "installing $pkgname via spc..."
            spc_cmd install "$pkg_archive" || die "spc failed to install cached package"
            return 0
        else
            info "cache exists but is stale (dependency update detected)"
            rm -f "$pkg_archive"
        fi
    fi

    if [ "$is_legacy" -eq 1 ]; then
        msg "installing $pkgname (legacy mode)..."
        local slog nfiles
        slog=$(tmp_file "strace-$pkgname")
        nfiles=$(tmp_file "nfiles-$pkgname")
        staging_dir="${BUILDBASE}/pkg-legacy-${pkgname}-${ver_raw}"

        rm -rf "$staging_dir"
        mkdir -p "$staging_dir"

        cd "$dir" || die "cannot cd to $dir"

        if ! strace -f -y -qq \
            -e trace=open,openat,creat,rename,renameat,renameat2,symlink,symlinkat,link,linkat \
            -o "$slog" env DISTDIR="$DISTDIR" BUILDBASE="$BUILDBASE" TMPDIR="$TMPDIR" \
            sh "$makefile" install; then
            rm -f "$slog" "$nfiles"
            die "legacy install failed for $pkg"
        fi

        parse_strace "$slog" > "$nfiles"

        msg "capturing legacy files..."
        while read -r f; do
             if [ -e "$f" ]; then
                 mkdir -p "$staging_dir/$(dirname "$f")"
                 cp -a "$f" "$staging_dir/$f"
             fi
        done < "$nfiles"

        rm -f "$slog" "$nfiles"

        msg "packaging legacy capture..."
        spc_cmd create "$staging_dir" "$pkg_archive" || die "spc failed to create package"

        msg "registering $pkgname via spc..."
        SPC_FORCE=1 spc_cmd install "$pkg_archive" || die "spc failed to register package"

        rm -rf "$staging_dir"

    else
        staging_dir="${BUILDBASE}/pkg-${pkgname}-${ver_raw}"

        if [ ! -d "$staging_dir" ]; then
            die "staging directory not found: $staging_dir (build not run?)"
        fi

        if [ "${ver#git:}" != "$ver" ]; then
            printf 'commit: %s\n' "${ver#git:}" > "$staging_dir/.info"
        fi

        msg "packaging $pkgname..."
        spc_cmd create "$staging_dir" "$pkg_archive" || die "spc failed to create package"

        msg "installing $pkgname via spc..."
        spc_cmd install "$pkg_archive" || die "spc failed to install package"
    fi
}

clean_package() {
    local pkg="$1" dir makefile

    dir=$(find_package "$pkg") || die "package $pkg not found"

    if makefile=$(get_makefile "$dir"); then
        msg "cleaning $pkg"
        cd "$dir" || die "cannot cd to $dir"
        sh "$makefile" clean || die "clean failed for $pkg"
    else
        die "no build script found for $pkg"
    fi
}

remove_package() {
    local pkg="$1" dir pkgname makefile

    dir=$(find_package "$pkg") || die "package $pkg not found"
    pkgname=$(get_package_name_var "$pkg")
    [ -z "$pkgname" ] && pkgname="${dir##*/}"

    msg "removing $pkgname"
    spc_cmd remove "$pkgname" || die "spc failed to remove package"

    # Cleanup build artifacts if present
    if makefile=$(get_makefile "$dir"); then
        cd "$dir"
        sh "$makefile" clean >/dev/null 2>&1 || true
    fi
}

do_make() {
    local pkg="$1" plan deps

    # Check existence before proceeding
    if ! find_package "$pkg" >/dev/null; then
        die "package '$pkg' not found"
    fi

    plan=$(tmp_file "plan")
    deps=$(build_ordered_deps "$pkg")

    if [ -n "$deps" ]; then
        printf '%s\n' "$deps" > "$plan"
    else
        > "$plan"
    fi

    if [ "$DTR_SKIP_CONFIRM" != "1" ]; then
        local is_reinstall=0
        if is_installed "$pkg"; then
            is_reinstall=1
        fi

        $log_printf '\n<bold>build plan for %s:</bold>\n' "$pkg"
        print_dep_tree "$pkg" " " 1
        $log_printf "\n"

        if [ "$is_reinstall" -eq 1 ]; then
             $log_printf "package ${_str_highlight_f} is already installed.\n" "$pkg"
             confirm_action "rebuild ${_str_highlight_o}${pkg}${_str_highlight_c}?" || { rm -f "$plan"; return 1; }
        else
             confirm_action "proceed with build?" || { rm -f "$plan"; return 1; }
        fi
    fi

    [ -f "$plan" ] && while IFS= read -r dep; do
        [ -n "$dep" ] && [ "$dep" != "$pkg" ] || continue
        is_installed "$dep" && continue
        msg "installing dependency: $dep"
        build_package "$dep"
        install_package "$dep"
    done < "$plan"

    build_package "$pkg"
    rm -f "$plan"
}

do_make_nodeps() {
    local pkg="$1"

    # Check existence before proceeding
    if ! find_package "$pkg" >/dev/null; then
        die "package '$pkg' not found"
    fi

    if [ "$DTR_SKIP_CONFIRM" != "1" ]; then
        local is_reinstall=0
        if is_installed "$pkg"; then
            is_reinstall=1
        fi

        $log_printf '\n<bold>building (no deps) %s:</bold>\n' "$pkg"

        if [ "$is_reinstall" -eq 1 ]; then
             $log_printf "package ${_str_highlight_f} is already installed.\n" "$pkg"
             confirm_action "rebuild ${_str_highlight_o}${pkg}${_str_highlight_c}?" || return 1
        else
             confirm_action "proceed with build?" || return 1
        fi
    fi

    build_package "$pkg"
}

# === SYNC & UPGRADE ===
get_remote_branch() {
    local remote="${DTR_REMOTE}" branch="${DTR_BRANCH}" fallback="main"

    if git show-ref --verify --quiet "refs/remotes/$remote/$branch"; then
        printf '%s/%s' "$remote" "$branch"
    elif git show-ref --verify --quiet "refs/remotes/$remote/$fallback"; then
        printf '%s/%s' "$remote" "$fallback"
    else
        die "neither $remote/$branch nor $remote/$fallback found"
    fi
}
sync_ports() {
    msg "syncing ports tree"

    local current_remote

    if [ -d "$DTR_DIR/.git" ]; then
        cd "$DTR_DIR" || die "cannot cd to $DTR_DIR"
        current_remote=$(git config "remote.$DTR_REMOTE.url" 2>/dev/null || true)

        if [ -n "$current_remote" ] &&
           [ "$current_remote" != "$DEFAULT_REPO" ] &&
           [ "$current_remote" != "${DEFAULT_REPO}.git" ]; then
            warn "current ports tree points to unexpected remote: $current_remote"
            info "expected: $DEFAULT_REPO"
            confirm_action "proceed with fetch/reset anyway?" || { msg "sync aborted"; return 1; }
        fi

        msg "fetching and resetting existing repository"
        git fetch --quiet "$DTR_REMOTE" || die "git fetch failed"
        local ref
        ref=$(get_remote_branch)
        git reset --hard "$ref" || die "git reset failed"
    else
        if [ -d "$DTR_DIR" ]; then
            warn "directory $DTR_DIR exists but is not a git repository"
            confirm_action "remove it and clone fresh repository?" || { msg "sync aborted"; return 1; }
            rm -rf "$DTR_DIR" || die "failed to remove existing directory"
        fi

        msg "cloning fresh ports tree from $DEFAULT_REPO"
        git clone --quiet "$DEFAULT_REPO" "$DTR_DIR" || die "clone failed"
    fi

    if [ -f "$DTR_DIR/dtr" ]; then
        cp -f "$DTR_DIR/dtr" /bin/dtr || die "failed to copy $DTR_DIR/dtr to /bin/dtr"
    else
        warn "missing $DTR_DIR/dtr; skipping /bin/dtr update"
    fi

    if [ -f "$DTR_DIR/spc" ]; then
        cp -f "$DTR_DIR/spc" /bin/spc || die "failed to copy $DTR_DIR/spc to /bin/spc"
    else
        warn "missing $DTR_DIR/spc; skipping /bin/spc update"
    fi

    msg "ports tree synced"
}
check_package_update() {
    local pkg="$1" outfile="$2" ver_new ver_old

    ver_new=$(get_package_version "$pkg")
    ver_new=$(resolve_git_version "$ver_new" "$pkg")

    # We query spc info for installed details
    if is_installed "$pkg"; then
        ver_old=$(spc_cmd info "$pkg" | grep "^version:" | cut -d: -f2- | sed 's/^ *//')
    else
        ver_old=""
    fi

    if [ -n "$ver_new" ] && [ -n "$ver_old" ] && [ "$ver_new" != "$ver_old" ]; then
        printf '%s|version|%s|%s\n' "$pkg" "$ver_old" "$ver_new" >> "$outfile"
    fi
}
do_upgrade() {
    spc_cmd list >/dev/null 2>&1 || { msg "no packages installed"; return 0; }

    msg "checking for updates"

    local pkg upg
    upg=$(tmp_file "upgrade")
    > "$upg"

    spc_cmd list | cut -d'+' -f1 | while IFS= read -r pkg; do
        [ -n "$pkg" ] || continue
        check_package_update "$pkg" "$upg" &
    done
    wait

    if [ ! -s "$upg" ]; then
        msg "all packages up to date"
        rm -f "$upg"
        return 0
    fi

    $log_printf '\npackages with updates:\n'
    while IFS='|' read -r pkg t o n; do
        if [ "$t" = "version" ]; then
            $log_printf '  \033[1m%s\033[m: %s -> %s\n' "$pkg" "$o" "$n"
        else
            $log_printf '  \033[1m%s\033[m: %.8s -> %.8s\n' "$pkg" "$o" "$n"
        fi
    done < "$upg"

    local link_deps all_deps
    link_deps=$(tmp_file "link")
    all_deps=$(tmp_file "all")
    > "$link_deps"
    > "$all_deps"

    while IFS='|' read -r pkg t o n; do
        find_reverse_deps "$pkg" "link" >> "$link_deps"
        find_reverse_deps "$pkg" "" >> "$all_deps"
    done < "$upg"

    $log_printf '\nwill rebuild:\n'
    sort -u "$link_deps" | grep -v '^$' > "$link_deps.s" || : > "$link_deps.s"
    sort -u "$all_deps" | grep -v '^$' > "$all_deps.s" || : > "$all_deps.s"

    if [ -s "$link_deps.s" ]; then
        $log_printf '  \033[1mlink-time:\033[m\n'
        sed 's/^/      /' "$link_deps.s"
    else
        $log_printf '  (no dependents)\n'
    fi

    if [ -s "$all_deps.s" ] && ! cmp -s "$link_deps.s" "$all_deps.s"; then
        $log_printf '  \033[1mall deps:\033[m\n'
        sed 's/^/      /' "$all_deps.s"
    fi

    rm -f "$link_deps" "$all_deps" "$link_deps.s" "$all_deps.s"

    local rebuild_scope="link"
    if [ "$DTR_SKIP_CONFIRM" != "1" ]; then
        $log_printf '\nrebuild scope:\n'
        $log_printf '  [1] link-time dependents\n'
        $log_printf '  [2] all dependents\n'
        $log_printf '  [3] target package only\n'
        $log_printf '  [4] exit\n'
        $log_printf 'select option [1]: '
        read -r choice </dev/tty
        case "$choice" in
            2) rebuild_scope="" ;;
            3) rebuild_scope="none" ;;
            4) rm -f "$upg"; return 0 ;;
            *) rebuild_scope="link" ;;
        esac
    fi

    local updated=0 rebuilt_total=0
    while IFS='|' read -r pkg t o n; do
        msg "upgrading $pkg ($t)"
        DTR_SKIP_CONFIRM=1 do_make "$pkg" &&
            install_package "$pkg" &&
            clean_package "$pkg" &&
            updated=$((updated + 1))

        if [ "$rebuild_scope" != "none" ]; then
            rebuilt_total=$((rebuilt_total + $(rebuild_dependents "$pkg" "$rebuild_scope")))
        fi
    done < "$upg"

    rm -f "$upg"
    msg "upgraded $updated package(s), rebuilt $rebuilt_total dependent(s)"
}

# === LISTING & SEARCH ===
# laf: List all from repo, enriched with spc data
list_all_full() {
    $log_printf 'available packages in %s:\n' "$DTR_DIR"

    # Search for ndmake.sh only
    find "$DTR_DIR" -mindepth 3 -maxdepth 3 -type f -name "$DTR_NEW_MAKE" -print |
        for_each_line dirname | for_each_line basename | sort -u |
        while read -r pkg; do
            if is_installed "$pkg"; then
                 $log_printf '  [I] '
            else
                 $log_printf '  [ ] '
            fi
            format_package_info "$pkg" '$pkg$ver$maint'
        done
}

# lif: List installed via spc passthrough
list_installed_full() {
    spc_cmd list
}

list_deps() {
    local pkg="$1" dir depsfile dep name type

    dir=$(find_package "$pkg") || die "package $pkg not found"
    depsfile="$dir/deps"

    $log_printf 'dependencies for %s (/ = link-time, > = runtime, . = build-time):\n' "$pkg"

    if [ -f "$depsfile" ] && grep -qv '^\s*#' "$depsfile" 2>/dev/null; then
        read_deps_file "$depsfile" | while IFS= read -r dep; do
            name=$(parse_dep_name "$dep")
            type=$(parse_dep_type "$dep")
            case "$type" in
                link)    $log_printf '  /%s\n' "$name" ;;
                runtime) $log_printf '  >%s\n' "$name" ;;
                build)   $log_printf '  .%s\n' "$name" ;;
            esac
        done
    else
        $log_printf '  (none)\n'
    fi
}
search_packages() {
    local query="$1"
    [ -z "$query" ] && die "search query required"

    msg "searching for: $query"

    find "$DTR_DIR" -mindepth 3 -maxdepth 3 -type f -name "info" |
    while read -r infofile; do
        if grep -Ei "^(name|description):.*$query" "$infofile" >/dev/null; then
             local pkgdir
             pkgdir=$(dirname "$infofile")
             $log_printf '  '
             format_package_info "${pkgdir##*/}" '$pkg$desc'
        fi
    done
}

# === INFO MANAGEMENT ===
show_info() {
    local pkg="$1" dir infofile

    dir=$(find_package "$pkg") || die "package $pkg not found"
    infofile="$dir/info"
    [ -f "$infofile" ] || die "info file not found for $pkg"

    cat "$infofile"
    $log_printf '\n'
}
populate_info() {
    [ -d "$DTR_DIR/.git" ] || die "$DTR_DIR is not a git repository"

    msg "populating info fields from git history"
    local authors_tmp
    authors_tmp=$(tmp_file "authors")

    find "$DTR_DIR" -mindepth 3 -maxdepth 3 -type f -name "$DTR_NEW_MAKE" |
    while read -r makefile; do
        local pkgdir pkgname infofile creator_raw maintainer_md contributors_md
        local name desc license
        pkgdir=$(dirname "$makefile")
        pkgname="${pkgdir##*/}"
        infofile="$pkgdir/info"

        cd "$DTR_DIR" || continue

        # Read existing fields
        if [ -f "$infofile" ]; then
            name=$(get_info_field "$infofile" "name")
            desc=$(get_info_field "$infofile" "description")
            license=$(get_info_field "$infofile" "license")
        fi

        # Determine creator (first committer to build script)
        creator_raw=$(git log --reverse --format='%an <%ae>' -- "$makefile" | head -n 1)
        [ -z "$creator_raw" ] && continue

        # Get all contributors sorted by commit count
        git log --format='%an <%ae>' -- "$makefile" |
            sort | uniq -c | sort -rn > "$authors_tmp"

        # Build markdown strings (sanitize names: spaces -> underscores)
        maintainer_md=$(echo "$creator_raw" | sed 's/^\(.*\) <\(.*\)>$/[\1](\2)/' | sed 's/\[\([^]]*\)\]/[\1]/' | sed 's/\[\([^]]*\) /[\1_/g' | sed 's/ \([^]]*\)\]/_\1]/g')
        contributors_md=""

        # Filter creator from contributors, format others
        local contrib_list
        contrib_list=$(grep -vF "$creator_raw" "$authors_tmp" | sed -E 's/^[[:space:]]*[0-9]+[[:space:]]+//')

        if [ -n "$contrib_list" ]; then
            contributors_md=$(echo "$contrib_list" | sed 's/^\(.*\) <\(.*\)>$/[\1](\2)/' | sed 's/\[\([^]]*\)\]/[\1]/' | sed 's/\[\([^]]*\) /[\1_/g' | sed 's/ \([^]]*\)\]/_\1]/g' | paste -sd ',' - | sed 's/,/, /g')
        fi

        # Update info file (create if doesn't exist)
        if [ ! -f "$infofile" ]; then
            touch "$infofile"
        fi

        # Remove existing maintainer/contributors fields
        sed -i '/^maintainer:/d' "$infofile"
        sed -i '/^contributors:/d' "$infofile"

        # Set proper name if empty
        if [ -z "$name" ]; then
            printf 'name: %s\n' "$pkgname" >> "$infofile"
        fi

        # Warn if description is empty
        [ -z "$desc" ] && warn "package $pkgname: description field is empty"

        # Warn if license is empty
        [ -z "$license" ] && warn "package $pkgname: license field is empty"

        # Append maintainer and contributors
        printf 'maintainer: %s\n' "$maintainer_md" >> "$infofile"
        if [ -n "$contributors_md" ]; then
            printf 'contributors: %s\n' "$contributors_md" >> "$infofile"
        fi

        info "updated: $pkgname"
    done

    rm -f "$authors_tmp"
    msg "info population complete"
}
generate_dmake_scripts() {
    local dir="${1:-$DTR_DIR}"
    [ -d "$dir" ] || die "directory $dir does not exist"

    find "$dir" -mindepth 1 -maxdepth 1 -type d |
    while read -r d; do
        local makefile pkgname
        makefile="$d/$DTR_NEW_MAKE"
        [ -f "$makefile" ] && continue

        pkgname="${d##*/}"
        msg "creating $DTR_NEW_MAKE for $pkgname"

        cat > "$makefile" <<'EOF'
#!/bin/sh
# ndmake.sh template for $pkgname

case "${1:-}" in
    make)    ;;
    install) ;;
    clean)   ;;
    remove)  ;;
    *) echo "usage: $0 {make|install|clean|remove}"; exit 1 ;;
esac
EOF
        chmod +x "$makefile"
    done
}

# === EXTENSIONS ===
find_extension() {
    local ext="$1" dir

    for dir in $EXTENSION_DIRS; do
        if [ -d "$dir" ] && [ -f "$dir/$ext" ]; then
            printf '%s' "$dir/$ext"
            return 0
        fi
    done
    return 1
}

call_extension() {
    local ext="$1" ext_path
    shift

    ext_path=$(find_extension "$ext") || return 1
    sh "$ext_path" "$@"
}
process_chain() {
    local chain="$1" i=0 c next_c

    while [ $i -lt ${#chain} ]; do
        c=$(printf '%s' "$chain" | cut -c$((i + 1)))
        i=$((i + 1))

        case "$c" in
            m) do_make "$pkg" ;;
            d) do_make_nodeps "$pkg" ;;
            i) install_package "$pkg" ;;
            c) clean_package "$pkg" ;;
            r) remove_package "$pkg" ;;
            s) sync_ports ;;
            u) do_upgrade ;;
            g) generate_dmake_scripts "$pkg" ;;
            f) show_info "$pkg" ;;
            l)
                next_c=$(printf '%s' "$chain" | cut -c$((i + 1)))
                case "$next_c" in
                    a) list_all_full; return ;;
                    i) list_installed_full; return ;;
                    d) [ -n "$pkg" ] && list_deps "$pkg"; return ;;
                    *) die "invalid list command: l$next_c (use la, li, or ld)" ;;
                esac
                i=$((i + 1))
                ;;
            *)
                call_extension "$c" "$pkg" || die "unknown command character: $c (no '$c' extension found)"
                ;;
        esac
    done
}

# === MAIN ===
main() {
    if [ $# -eq 0 ]; then
        cat <<EOF
usage: $PROG_NAME [options] [y] <cmd> <pkgs>
       $PROG_NAME m|i|c|r|d|g <pkgs>
       $PROG_NAME la|li|laf|lif|ld|sp|f <pkgs>
       $PROG_NAME s|u|pi|se
       $PROG_NAME mic|dic <pkgs>  (build+install+clean; d=no deps)

options:
  --yes, -y               skip confirmation prompts
  --ports <dir>           ports tree location (default: ./ports beside dtr)
  --spc <path>            spc binary path (default: ./bs-spc beside dtr)
  --rootfs <dir>          install/remove/list DB against this rootfs
  --target <triple>       cross target triple
  --libc <name>           libc hint for cross builds
  --sysroot <dir>         sysroot for cross builds/pkg-config
EOF
        exit 0
    fi

    while [ $# -gt 0 ]; do
        case "${1:-}" in
            -h|--help|help)
                cat <<EOF
usage: $PROG_NAME [options] [y] <cmd> <pkgs>
       $PROG_NAME m|i|c|r|d|g <pkgs>
       $PROG_NAME la|li|laf|lif|ld|sp|f <pkgs>
       $PROG_NAME s|u|pi|se
       $PROG_NAME mic|dic <pkgs>  (build+install+clean; d=no deps)

options:
  --yes, -y               skip confirmation prompts
  --ports <dir>           ports tree location (default: ./ports beside dtr)
  --spc <path>            spc binary path (default: ./bs-spc beside dtr)
  --rootfs <dir>          install/remove/list DB against this rootfs
  --target <triple>       cross target triple
  --libc <name>           libc hint for cross builds
  --sysroot <dir>         sysroot for cross builds/pkg-config
EOF
                exit 0
                ;;
            y|-y|--yes)
                DTR_SKIP_CONFIRM=1
                shift
                ;;
            --ports)
                [ $# -lt 2 ] && die "missing value for --ports"
                DTR_DIR="$2"
                shift 2
                ;;
            --spc)
                [ $# -lt 2 ] && die "missing value for --spc"
                DTR_SPC_BIN="$2"
                shift 2
                ;;
            --rootfs)
                [ $# -lt 2 ] && die "missing value for --rootfs"
                DTR_ROOTFS="$2"
                shift 2
                ;;
            --target)
                [ $# -lt 2 ] && die "missing value for --target"
                DTR_TARGET="$2"
                shift 2
                ;;
            --libc)
                [ $# -lt 2 ] && die "missing value for --libc"
                DTR_LIBC="$2"
                shift 2
                ;;
            --sysroot)
                [ $# -lt 2 ] && die "missing value for --sysroot"
                DTR_SYSROOT="$2"
                shift 2
                ;;
            --)
                shift
                break
                ;;
            -*)
                die "unknown option: $1"
                ;;
            *)
                break
                ;;
        esac
    done

    [ $# -eq 0 ] && die "command required"
    setup_cross_env

    local cmd="$1"
    case "$cmd" in
        y*)
            DTR_SKIP_CONFIRM=1
            cmd="${cmd#y}"
            ;;
    esac
    shift

    case "$cmd" in
        chill)
            chill "$0" && exit 0
            ;;
        laf|la)
            list_all_full && exit 0
            ;;
        lif|li)
            list_installed_full && exit 0
            ;;
        s|sync)
            sync_ports && exit 0
            ;;
        u|upgrade)
            do_upgrade && exit 0
            ;;
        pi|populate-info)
            populate_info && exit 0
            ;;
        se|search)
            [ $# -eq 0 ] && die "search query required"
            search_packages "$*" && exit 0
            ;;
    esac

    # Check if command is valid before requiring package
    case "$cmd" in
        ld|sp|f|g|gen|m|make|i|install|c|clean|r|remove|d)
            [ $# -eq 0 ] && die "package required for '$cmd'"
            ;;
        *)
            # Check if it's an extension or valid chain command
            local ext_path is_valid=0
            ext_path=$(find_extension "$cmd") && is_valid=1

            # Check if it's a valid chain (only contains valid command chars)
            if [ "$is_valid" -eq 0 ]; then
                local i=0 c
                while [ $i -lt ${#cmd} ]; do
                    c=$(printf '%s' "$cmd" | cut -c$((i + 1)))
                    case "$c" in
                        m|i|c|r|s|u|g|f|l|d) is_valid=1 ;;
                        *)
                            # Could still be an extension for this char
                            find_extension "$c" >/dev/null 2>&1 && is_valid=1 || is_valid=0
                            [ "$is_valid" -eq 0 ] && break
                            ;;
                    esac
                    i=$((i + 1))
                done
            fi

            if [ "$is_valid" -eq 0 ]; then
                die "invalid command: '$cmd'"
            fi

            [ $# -eq 0 ] && die "package required for '$cmd'"
            ;;
    esac

    for pkg in "$@"; do
        pkg=$(resolve_package_arg "$pkg")

        case "$cmd" in
            ld)
                list_deps "$pkg"
                ;;
            sp)
                local found
                found=$(find_package "$pkg")
                if [ -n "$found" ]; then
                    printf '%s\n' "$found"
                else
                    printf 'not found\n'
                fi
                ;;
            f)
                show_info "$pkg"
                ;;
            g|gen)
                generate_dmake_scripts "$pkg"
                ;;
            m|make)
                do_make "$pkg"
                ;;
            i|install)
                install_package "$pkg"
                ;;
            c|clean)
                clean_package "$pkg"
                ;;
            r|remove)
                remove_package "$pkg"
                ;;
            d)
                do_make_nodeps "$pkg"
                ;;
            *)
                local ext_path
                ext_path=$(find_extension "$cmd")
                if [ -n "$ext_path" ]; then
                    sh "$ext_path" "$pkg"
                else
                    process_chain "$cmd"
                fi
                ;;
        esac
    done

    exit 0
}

main "$@"
