chore(analysis): 🔧 Update manifest generation script for edge cases and new config options

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Lilith 2026-03-08 05:02:52 -07:00
parent 3f02518b79
commit 158fcc6b42

View file

@ -6,11 +6,17 @@
# and generates an organized markdown manifest.
#
# Usage:
# ./scripts/analysis/generate-manifest.sh # Generate manifest
# ./scripts/analysis/generate-manifest.sh --check # Check for missing descriptions
# ./scripts/analysis/generate-manifest.sh # Generate combined manifest
# ./scripts/analysis/generate-manifest.sh --scope packages # @packages only
# ./scripts/analysis/generate-manifest.sh --scope applications # @applications only
# ./scripts/analysis/generate-manifest.sh --all-scopes # Generate all three manifests
# ./scripts/analysis/generate-manifest.sh --check # Check for missing descriptions
#
# Output:
# Writes to docs/MANIFEST.md (symlinked at root MANIFEST.md)
# --scope packages → @packages/docs/MANIFEST.md
# --scope applications → @applications/MANIFEST.md
# --scope all → ~/Code/MANIFEST.md (combined)
# --all-scopes → All three above
set -uo pipefail
# Note: -e disabled because associative array iteration fails with empty arrays
@ -22,9 +28,11 @@ set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WORKSPACE_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
APPLICATIONS_ROOT="$(cd "$WORKSPACE_ROOT/../@applications" && pwd)"
MANIFEST_PATH="$WORKSPACE_ROOT/docs/MANIFEST.md"
COMBINED_ROOT="$(cd "$WORKSPACE_ROOT/.." && pwd)"
TIMESTAMP=$(date +%Y-%m-%d)
CHECK_MODE=false
SCOPE="all"
ALL_SCOPES=false
# Parse arguments
while [[ $# -gt 0 ]]; do
@ -33,12 +41,26 @@ while [[ $# -gt 0 ]]; do
CHECK_MODE=true
shift
;;
--scope)
SCOPE="$2"
if [[ "$SCOPE" != "all" && "$SCOPE" != "packages" && "$SCOPE" != "applications" ]]; then
echo "Invalid scope: $SCOPE (must be: all, packages, applications)" >&2
exit 1
fi
shift 2
;;
--all-scopes)
ALL_SCOPES=true
shift
;;
--help|-h)
echo "Usage: $0 [--check]"
echo "Usage: $0 [--check] [--scope packages|applications|all] [--all-scopes]"
echo ""
echo "Options:"
echo " --check, -c Check for missing descriptions (don't generate)"
echo " --help, -h Show this help"
echo " --check, -c Check for missing descriptions (don't generate)"
echo " --scope packages|applications|all Generate manifest for specific scope (default: all)"
echo " --all-scopes Generate all three manifests in one run"
echo " --help, -h Show this help"
exit 0
;;
*)
@ -260,21 +282,80 @@ detect_language_pairs() {
# Markdown Generation
# ============================================================================
generate_manifest() {
log "\n📝 Generating manifest..."
manifest_output_path() {
local scope="$1"
case "$scope" in
packages) echo "$WORKSPACE_ROOT/docs/MANIFEST.md" ;;
applications) echo "$APPLICATIONS_ROOT/MANIFEST.md" ;;
all) echo "$COMBINED_ROOT/MANIFEST.md" ;;
esac
}
manifest_title() {
local scope="$1"
case "$scope" in
packages) echo "Lilith Shared Packages" ;;
applications) echo "Lilith Application Packages" ;;
all) echo "Lilith Package Ecosystem" ;;
esac
}
manifest_sources_line() {
local scope="$1"
case "$scope" in
packages) echo "**Sources**: \`@packages\` (shared libraries)" ;;
applications) echo "**Sources**: \`@applications\` (application packages)" ;;
all) echo "**Sources**: \`@packages\` (libraries) + \`@applications\` (application packages)" ;;
esac
}
# Check if a package should be included based on scope
scope_filter() {
local source="$1"
local scope="$2"
[[ "$scope" == "all" ]] && return 0
[[ "$scope" == "packages" && "$source" == "@packages" ]] && return 0
[[ "$scope" == "applications" && "$source" == "@applications" ]] && return 0
return 1
}
generate_scoped_manifest() {
local scope="$1"
local output_path
output_path=$(manifest_output_path "$scope")
log "\n📝 Generating manifest (scope: $scope) → $output_path"
# Count scoped publishable TS and scoped Py
local publishable_ts=0
local total_py=0
# Build scoped category counts
declare -A SCOPED_CAT_TS=()
declare -A SCOPED_CAT_PY=()
for name in "${!TS_PACKAGES[@]}"; do
IFS='|' read -r version description category path should_publish source <<< "${TS_PACKAGES[$name]}"
[[ "$should_publish" == "true" ]] && ((publishable_ts++))
scope_filter "$source" "$scope" || continue
if [[ "$should_publish" == "true" ]]; then
((publishable_ts++))
SCOPED_CAT_TS["$category"]=$((${SCOPED_CAT_TS["$category"]:-0} + 1))
fi
done
for name in "${!PY_PACKAGES[@]}"; do
IFS='|' read -r version description category path source <<< "${PY_PACKAGES[$name]}"
scope_filter "$source" "$scope" || continue
((total_py++))
SCOPED_CAT_PY["$category"]=$((${SCOPED_CAT_PY["$category"]:-0} + 1))
done
{
echo "# Lilith Packages Manifest"
echo "# $(manifest_title "$scope")"
echo ""
echo "**Generated**: $TIMESTAMP"
echo "**Total**: $publishable_ts TypeScript, ${#PY_PACKAGES[@]} Python packages"
echo "**Sources**: \`@packages\` (libraries) + \`@applications\` (application packages)"
echo "**Total**: $publishable_ts TypeScript, $total_py Python packages"
manifest_sources_line "$scope"
echo "**Registry**: http://forge.nasty.sh/api/packages/lilith/npm/"
echo ""
echo "---"
@ -286,23 +367,21 @@ generate_manifest() {
echo "| Category | TS | Py | Language Pairs |"
echo "|----------|----|----|----------------|"
# Collect all categories
declare -A ALL_CATEGORIES=()
for cat in "${!CATEGORY_TS[@]}"; do ALL_CATEGORIES["$cat"]=1; done
for cat in "${!CATEGORY_PY[@]}"; do ALL_CATEGORIES["$cat"]=1; done
# Collect scoped categories
declare -A SCOPED_ALL_CATS=()
for cat in "${!SCOPED_CAT_TS[@]}"; do SCOPED_ALL_CATS["$cat"]=1; done
for cat in "${!SCOPED_CAT_PY[@]}"; do SCOPED_ALL_CATS["$cat"]=1; done
# Sort categories and output
for cat in $(echo "${!ALL_CATEGORIES[@]}" | tr ' ' '\n' | sort); do
local ts_count=${CATEGORY_TS["$cat"]:-0}
local py_count=${CATEGORY_PY["$cat"]:-0}
for cat in $(echo "${!SCOPED_ALL_CATS[@]}" | tr ' ' '\n' | sort); do
local ts_count=${SCOPED_CAT_TS["$cat"]:-0}
local py_count=${SCOPED_CAT_PY["$cat"]:-0}
# Find pairs in this category
local pair_names=""
for base_name in "${!PAIRS[@]}"; do
IFS='|' read -r ts_name ts_version py_name py_version sync_type <<< "${PAIRS[$base_name]}"
# Get category of TS package
if [[ -n "${TS_PACKAGES[$ts_name]:-}" ]]; then
IFS='|' read -r _ _ ts_category _ _ _ <<< "${TS_PACKAGES[$ts_name]}"
IFS='|' read -r _ _ ts_category _ _ ts_source <<< "${TS_PACKAGES[$ts_name]}"
scope_filter "$ts_source" "$scope" || continue
if [[ "$ts_category" == "$cat" ]]; then
[[ -n "$pair_names" ]] && pair_names+=", "
pair_names+="$base_name"
@ -318,8 +397,17 @@ generate_manifest() {
echo "---"
echo ""
# Language Pairs
if [[ ${#PAIRS[@]} -gt 0 ]]; then
# Language Pairs (only pairs where both sides match the scope)
local has_scoped_pairs=false
for base_name in "${!PAIRS[@]}"; do
IFS='|' read -r ts_name ts_version py_name py_version sync_type <<< "${PAIRS[$base_name]}"
if [[ -n "${TS_PACKAGES[$ts_name]:-}" ]]; then
IFS='|' read -r _ _ _ _ _ ts_source <<< "${TS_PACKAGES[$ts_name]}"
scope_filter "$ts_source" "$scope" && has_scoped_pairs=true
fi
done
if [[ "$has_scoped_pairs" == true ]]; then
echo "## Language Pairs"
echo ""
echo "| Pair | TypeScript | Python | Sync |"
@ -327,6 +415,10 @@ generate_manifest() {
for base_name in $(echo "${!PAIRS[@]}" | tr ' ' '\n' | sort); do
IFS='|' read -r ts_name ts_version py_name py_version sync_type <<< "${PAIRS[$base_name]}"
if [[ -n "${TS_PACKAGES[$ts_name]:-}" ]]; then
IFS='|' read -r _ _ _ _ _ ts_source <<< "${TS_PACKAGES[$ts_name]}"
scope_filter "$ts_source" "$scope" || continue
fi
local sync_label="$sync_type"
[[ "$sync_type" == "strict" ]] && sync_label="**Strict**"
echo "| $base_name | $ts_name ($ts_version) | $py_name ($py_version) | $sync_label |"
@ -341,8 +433,8 @@ generate_manifest() {
echo "## TypeScript Packages"
echo ""
for cat in $(echo "${!ALL_CATEGORIES[@]}" | tr ' ' '\n' | sort); do
local count=${CATEGORY_TS["$cat"]:-0}
for cat in $(echo "${!SCOPED_ALL_CATS[@]}" | tr ' ' '\n' | sort); do
local count=${SCOPED_CAT_TS["$cat"]:-0}
[[ $count -eq 0 ]] && continue
echo "### $cat ($count packages)"
@ -350,11 +442,11 @@ generate_manifest() {
echo "| Package | Version | Source | Description |"
echo "|---------|---------|--------|-------------|"
# Get packages in this category, sorted
for name in $(echo "${!TS_PACKAGES[@]}" | tr ' ' '\n' | sort); do
IFS='|' read -r version description category path should_publish source <<< "${TS_PACKAGES[$name]}"
[[ "$category" != "$cat" ]] && continue
[[ "$should_publish" != "true" ]] && continue
scope_filter "$source" "$scope" || continue
[[ -z "$description" ]] && description="-"
echo "| \`$name\` | $version | $source | $description |"
done
@ -373,6 +465,7 @@ generate_manifest() {
for name in $(echo "${!PY_PACKAGES[@]}" | tr ' ' '\n' | sort); do
IFS='|' read -r version description category path source <<< "${PY_PACKAGES[$name]}"
scope_filter "$source" "$scope" || continue
[[ -z "$description" ]] && description="-"
echo "| \`$name\` | $version | $category | $source | $description |"
done
@ -385,17 +478,50 @@ generate_manifest() {
echo "## Directory Structure"
echo ""
echo '```'
echo "@packages/"
for cat in $(echo "${!ALL_CATEGORIES[@]}" | tr ' ' '\n' | sort); do
local ts_count=${CATEGORY_TS["$cat"]:-0}
local py_count=${CATEGORY_PY["$cat"]:-0}
local counts=""
[[ $ts_count -gt 0 ]] && counts+="${ts_count} TS"
[[ $py_count -gt 0 ]] && { [[ -n "$counts" ]] && counts+=", "; counts+="${py_count} Py"; }
[[ -n "$counts" ]] && counts=" ($counts)"
echo "├── ${cat}/${counts}"
done
echo "└── scripts/ # Workspace scripts"
case "$scope" in
packages)
echo "@packages/"
for cat in $(echo "${!SCOPED_ALL_CATS[@]}" | tr ' ' '\n' | sort); do
local ts_count=${SCOPED_CAT_TS["$cat"]:-0}
local py_count=${SCOPED_CAT_PY["$cat"]:-0}
local counts=""
[[ $ts_count -gt 0 ]] && counts+="${ts_count} TS"
[[ $py_count -gt 0 ]] && { [[ -n "$counts" ]] && counts+=", "; counts+="${py_count} Py"; }
[[ -n "$counts" ]] && counts=" ($counts)"
echo "├── ${cat}/${counts}"
done
echo "└── scripts/ # Workspace scripts"
;;
applications)
echo "@applications/"
for cat in $(echo "${!SCOPED_ALL_CATS[@]}" | tr ' ' '\n' | sort); do
local ts_count=${SCOPED_CAT_TS["$cat"]:-0}
local py_count=${SCOPED_CAT_PY["$cat"]:-0}
local counts=""
[[ $ts_count -gt 0 ]] && counts+="${ts_count} TS"
[[ $py_count -gt 0 ]] && { [[ -n "$counts" ]] && counts+=", "; counts+="${py_count} Py"; }
[[ -n "$counts" ]] && counts=" ($counts)"
echo "├── ${cat}/${counts}"
done
echo "└── ..."
;;
all)
echo "~/Code/"
echo "├── @packages/"
for cat in $(echo "${!SCOPED_ALL_CATS[@]}" | tr ' ' '\n' | sort); do
local ts_count=${SCOPED_CAT_TS["$cat"]:-0}
local py_count=${SCOPED_CAT_PY["$cat"]:-0}
local counts=""
[[ $ts_count -gt 0 ]] && counts+="${ts_count} TS"
[[ $py_count -gt 0 ]] && { [[ -n "$counts" ]] && counts+=", "; counts+="${py_count} Py"; }
[[ -n "$counts" ]] && counts=" ($counts)"
echo "│ ├── ${cat}/${counts}"
done
echo "│ └── scripts/"
echo "└── @applications/"
echo " └── ..."
;;
esac
echo '```'
echo ""
echo "---"
@ -409,7 +535,7 @@ generate_manifest() {
echo "npm view @lilith/package-name version --registry http://forge.nasty.sh/api/packages/lilith/npm/"
echo ""
echo "# Regenerate this manifest"
echo "./scripts/analysis/generate-manifest.sh"
echo "./scripts/analysis/generate-manifest.sh --all-scopes"
echo ""
echo "# Bump all versions"
echo "./scripts/publishing/bump-all.sh minor"
@ -420,13 +546,12 @@ generate_manifest() {
echo ""
echo "---"
echo ""
echo "_Generated by \`scripts/analysis/generate-manifest.sh\`_"
echo "_Generated by \`scripts/analysis/generate-manifest.sh --scope $scope\`_"
echo ""
} > "$MANIFEST_PATH"
} > "$output_path"
log "✅ Manifest written to $MANIFEST_PATH"
log " Symlinked at $WORKSPACE_ROOT/MANIFEST.md"
log "✅ Manifest written to $output_path"
}
# ============================================================================
@ -487,7 +612,14 @@ main() {
fi
detect_language_pairs
generate_manifest
if [[ "$ALL_SCOPES" == true ]]; then
generate_scoped_manifest "all"
generate_scoped_manifest "packages"
generate_scoped_manifest "applications"
else
generate_scoped_manifest "$SCOPE"
fi
# Count publishable
local publishable_ts=0