diff --git a/analysis/generate-manifest.sh b/analysis/generate-manifest.sh index 0fdb304..1ad0756 100755 --- a/analysis/generate-manifest.sh +++ b/analysis/generate-manifest.sh @@ -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