chore: initialize qiming workspace repository

This commit is contained in:
Codex
2026-05-29 14:22:48 +08:00
commit bfd67a0f2c
10750 changed files with 1885711 additions and 0 deletions

View File

@@ -0,0 +1,423 @@
#!/bin/bash
# pnpm disk usage inspection script
echo "======================================"
echo "pnpm disk usage analyzer"
echo "======================================"
echo ""
# Ensure pnpm is installed
if ! command -v pnpm &> /dev/null; then
echo "❌ pnpm not found; install it first"
echo " npm install -g pnpm"
exit 1
fi
echo "✅ pnpm version: $(pnpm --version)"
echo ""
# Read PROJECT_SOURCE_DIR from env file
get_project_dir_from_env() {
local env_name=${1:-"development"}
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local project_root="$(dirname "$script_dir")"
local env_file="$project_root/env.$env_name"
if [ -f "$env_file" ]; then
local project_dir=$(grep "^PROJECT_SOURCE_DIR=" "$env_file" | cut -d'=' -f2)
if [ -n "$project_dir" ]; then
echo "$project_dir"
return 0
fi
fi
return 1
}
# Store path
echo "📁 pnpm store path:"
STORE_PATH=$(pnpm store path 2>/dev/null)
STORE_FILESYSTEM=""
if [ -n "$STORE_PATH" ]; then
echo " $STORE_PATH"
if [ -d "$STORE_PATH" ]; then
STORE_SIZE=$(du -sh "$STORE_PATH" 2>/dev/null | awk '{print $1}')
echo " Store size: $STORE_SIZE"
STORE_FILESYSTEM=$(df "$STORE_PATH" 2>/dev/null | tail -n 1 | awk '{print $1}')
if [ -n "$STORE_FILESYSTEM" ]; then
echo " Filesystem: $STORE_FILESYSTEM"
fi
fi
else
echo " ⚠️ Could not resolve store path"
fi
echo ""
# Store status
echo "📊 pnpm store status:"
STORE_STATUS_OUTPUT=$(pnpm store status 2>&1)
STORE_STATUS_EXIT_CODE=$?
if [ $STORE_STATUS_EXIT_CODE -eq 0 ]; then
echo "$STORE_STATUS_OUTPUT"
else
if echo "$STORE_STATUS_OUTPUT" | grep -q "ENOENT"; then
echo " ⚠️ Store index missing or corrupted"
echo " 💡 Try:"
echo " pnpm store prune"
else
echo " ⚠️ Could not read store status"
echo " Error: $(echo "$STORE_STATUS_OUTPUT" | head -n 1)"
fi
fi
echo ""
# Project directory resolution
# Priority: 1) CLI arg 2) PROJECT_SOURCE_DIR 3) env file 4) prompt
PROJECT_DIR=""
AUTO_DETECTED_DIR=""
SOURCE_INFO=""
if [ -n "$1" ]; then
AUTO_DETECTED_DIR="$1"
SOURCE_INFO="command-line argument"
elif [ -n "$PROJECT_SOURCE_DIR" ]; then
AUTO_DETECTED_DIR="$PROJECT_SOURCE_DIR"
SOURCE_INFO="env PROJECT_SOURCE_DIR"
else
ENV_NAME="${NODE_ENV:-development}"
AUTO_DETECTED_DIR=$(get_project_dir_from_env "$ENV_NAME")
if [ -z "$AUTO_DETECTED_DIR" ]; then
for env in development production test; do
AUTO_DETECTED_DIR=$(get_project_dir_from_env "$env")
if [ -n "$AUTO_DETECTED_DIR" ]; then
ENV_NAME="$env"
break
fi
done
fi
if [ -n "$AUTO_DETECTED_DIR" ]; then
SOURCE_INFO="config file env.$ENV_NAME"
fi
fi
if [ -n "$AUTO_DETECTED_DIR" ]; then
echo ""
echo "📂 Detected project directory (source: $SOURCE_INFO)"
echo " Path: $AUTO_DETECTED_DIR"
echo ""
read -p "👉 Press Enter to use this path, or type a different path: " USER_INPUT
if [ -n "$USER_INPUT" ]; then
PROJECT_DIR="$USER_INPUT"
echo "📝 Using entered project directory: $PROJECT_DIR"
else
PROJECT_DIR="$AUTO_DETECTED_DIR"
echo "✅ Using detected project directory"
fi
else
echo ""
echo "⚠️ Could not auto-detect project directory"
echo ""
echo "💡 You can:"
echo " - Pass a path: $0 /path/to/projects"
echo " - Set env: PROJECT_SOURCE_DIR=/path/to/projects $0"
echo " - Set NODE_ENV: NODE_ENV=development $0"
echo ""
read -p "📝 Project directory path (Enter to skip project scan): " USER_INPUT
if [ -n "$USER_INPUT" ]; then
PROJECT_DIR="$USER_INPUT"
echo "📂 Using entered project directory"
else
echo ""
echo "Skipping project scan..."
fi
fi
if [ -n "$PROJECT_DIR" ] && [ ! -d "$PROJECT_DIR" ]; then
echo ""
echo "⚠️ Project directory does not exist: $PROJECT_DIR"
echo ""
echo "Skipping project scan..."
PROJECT_DIR=""
fi
if [ -n "$PROJECT_DIR" ]; then
echo ""
echo "🔍 Scanning project directory: $PROJECT_DIR"
echo ""
if [ -d "$PROJECT_DIR" ]; then
PROJECT_FILESYSTEM=$(df "$PROJECT_DIR" 2>/dev/null | tail -n 1 | awk '{print $1}')
if [ -n "$PROJECT_FILESYSTEM" ]; then
echo "💾 Filesystem check:"
echo " Project filesystem: $PROJECT_FILESYSTEM"
if [ -n "$STORE_FILESYSTEM" ]; then
echo " Store filesystem: $STORE_FILESYSTEM"
echo ""
if [ "$PROJECT_FILESYSTEM" = "$STORE_FILESYSTEM" ]; then
echo " ✅ Project and store are on the same filesystem"
echo " 💡 Hard links work; disk savings apply"
else
echo " ⚠️ Project and store are on different filesystems"
echo " ❌ Hard links cannot cross filesystems; pnpm will copy files"
fi
else
echo " ⚠️ Could not determine store filesystem"
fi
echo ""
fi
fi
echo "📦 Per-project node_modules (apparent size):"
echo " ⚠️ Note: du double-counts hard links; real usage is lower"
TOTAL_SIZE_KB=0
COUNT=0
MAX_DISPLAY=5
while IFS= read -r dir; do
SIZE_HUMAN=$(du -sh "$dir" 2>/dev/null | awk '{print $1}')
SIZE_KB=$(du -sk "$dir" 2>/dev/null | awk '{print $1}')
PROJECT_NAME=$(echo "$dir" | sed "s|$PROJECT_DIR/||" | sed 's|/node_modules||')
if [ $COUNT -lt $MAX_DISPLAY ]; then
echo " [$PROJECT_NAME] $SIZE_HUMAN (includes hard-link double counting)"
fi
TOTAL_SIZE_KB=$((TOTAL_SIZE_KB + SIZE_KB))
((COUNT++))
done < <(find "$PROJECT_DIR" -name "node_modules" -type d -maxdepth 3 2>/dev/null)
if [ $COUNT -gt $MAX_DISPLAY ]; then
echo " ... $((COUNT - MAX_DISPLAY)) more not shown"
fi
if [ $TOTAL_SIZE_KB -gt 0 ]; then
if [ $TOTAL_SIZE_KB -gt 1048576 ]; then
TOTAL_SIZE_HUMAN=$(awk "BEGIN {printf \"%.1fG\", $TOTAL_SIZE_KB/1048576}")
elif [ $TOTAL_SIZE_KB -gt 1024 ]; then
TOTAL_SIZE_HUMAN=$(awk "BEGIN {printf \"%.1fM\", $TOTAL_SIZE_KB/1024}")
else
TOTAL_SIZE_HUMAN="${TOTAL_SIZE_KB}K"
fi
echo " Total apparent size: $TOTAL_SIZE_HUMAN (real usage is lower)"
fi
echo " Found $COUNT node_modules directories"
echo ""
echo "🗂️ Per-project .pnpm folders (apparent size):"
echo " ⚠️ Note: entries under .pnpm are hard links; little extra space per copy"
PNPM_COUNT=0
PNPM_TOTAL_SIZE_KB=0
while IFS= read -r dir; do
SIZE_HUMAN=$(du -sh "$dir" 2>/dev/null | awk '{print $1}')
SIZE_KB=$(du -sk "$dir" 2>/dev/null | awk '{print $1}')
PROJECT_NAME=$(echo "$dir" | sed "s|$PROJECT_DIR/||" | sed 's|/node_modules/.pnpm||')
if [ $PNPM_COUNT -lt $MAX_DISPLAY ]; then
echo " [$PROJECT_NAME] $SIZE_HUMAN (hard links, shared in store)"
fi
PNPM_TOTAL_SIZE_KB=$((PNPM_TOTAL_SIZE_KB + SIZE_KB))
((PNPM_COUNT++))
done < <(find "$PROJECT_DIR" -type d -path "*/node_modules/.pnpm" -maxdepth 4 2>/dev/null)
if [ $PNPM_COUNT -gt $MAX_DISPLAY ]; then
echo " ... $((PNPM_COUNT - MAX_DISPLAY)) more not shown"
fi
if [ $PNPM_TOTAL_SIZE_KB -gt 0 ]; then
if [ $PNPM_TOTAL_SIZE_KB -gt 1048576 ]; then
PNPM_TOTAL_SIZE_HUMAN=$(awk "BEGIN {printf \"%.1fG\", $PNPM_TOTAL_SIZE_KB/1048576}")
elif [ $PNPM_TOTAL_SIZE_KB -gt 1024 ]; then
PNPM_TOTAL_SIZE_HUMAN=$(awk "BEGIN {printf \"%.1fM\", $PNPM_TOTAL_SIZE_KB/1024}")
else
PNPM_TOTAL_SIZE_HUMAN="${PNPM_TOTAL_SIZE_KB}K"
fi
echo " Total apparent size: $PNPM_TOTAL_SIZE_HUMAN (all hard-linked to store)"
fi
echo " Found $PNPM_COUNT .pnpm directories"
echo ""
echo "💾 Filesystem usage (df):"
echo " Whole filesystem is more accurate than summing du:"
df -h "$PROJECT_DIR" | tail -n 1 | awk '{print " Filesystem: "$1, "| Used: "$3, "| Avail: "$4, "| Use: "$5}'
echo ""
fi
echo "======================================"
echo "💡 Important:"
echo "======================================"
echo ""
echo "⚠️ du counts hard-linked files multiple times!"
echo " Files under each projects .pnpm are hard links into the store."
echo " Real disk use ≈ store size + small symlink/metadata overhead."
echo " Often ~3050% of what naive du sums suggest."
echo ""
echo "✅ Ways to see real usage:"
echo " 1. pnpm store size (shown above)"
echo " 2. df -h for the whole filesystem"
echo " 3. Compare df before and after installs"
echo ""
echo "======================================"
echo "💡 Recommendations:"
echo "======================================"
echo ""
echo "1. Prune unused packages from the store:"
echo " pnpm store prune"
echo ""
echo "2. Prefer one store and projects on the same filesystem:"
echo " Keep projects and the store on the same volume when possible"
echo ""
echo "3. Tune per-project .npmrc for your registry and link strategy"
echo ""
if [ -n "$PROJECT_DIR" ] && [ -d "$PROJECT_DIR" ]; then
echo ""
read -p "🔍 Verify hard links between two projects? (y to start, Enter to skip): " VERIFY_HARDLINK
if [[ "$VERIFY_HARDLINK" =~ ^[Yy]$ ]]; then
echo ""
echo "======================================"
echo "🔗 Hard link verification"
echo "======================================"
echo ""
echo "💡 Project layout: $PROJECT_DIR/{projectId}"
echo ""
echo "📋 Project IDs under this directory (up to 5):"
PROJECT_IDS=$(find "$PROJECT_DIR" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; 2>/dev/null | head -5)
if [ -n "$PROJECT_IDS" ]; then
echo "$PROJECT_IDS" | while read -r pid; do
echo " - $pid"
done
else
echo " (none)"
fi
echo ""
read -p "👉 First project ID: " PROJECT_1_ID
if [ -z "$PROJECT_1_ID" ]; then
echo "❌ Project ID cannot be empty"
else
read -p "👉 Second project ID: " PROJECT_2_ID
if [ -z "$PROJECT_2_ID" ]; then
echo "❌ Project ID cannot be empty"
elif [ "$PROJECT_1_ID" = "$PROJECT_2_ID" ]; then
echo "❌ Enter two different project IDs"
else
echo ""
PROJECT_1="$PROJECT_DIR/$PROJECT_1_ID"
PROJECT_2="$PROJECT_DIR/$PROJECT_2_ID"
PROJECT_1_NAME="$PROJECT_1_ID"
PROJECT_2_NAME="$PROJECT_2_ID"
if [ ! -d "$PROJECT_1" ]; then
echo "❌ Project directory not found: $PROJECT_1"
elif [ ! -d "$PROJECT_2" ]; then
echo "❌ Project directory not found: $PROJECT_2"
else
echo "🔍 Comparing projects:"
echo "$PROJECT_1_NAME"
echo "$PROJECT_2_NAME"
echo ""
PNPM_DIR_1="$PROJECT_1/node_modules/.pnpm"
PNPM_DIR_2="$PROJECT_2/node_modules/.pnpm"
if [ ! -d "$PNPM_DIR_1" ]; then
echo "⚠️ $PROJECT_1_NAME: no node_modules/.pnpm"
echo " Path: $PNPM_DIR_1"
elif [ ! -d "$PNPM_DIR_2" ]; then
echo "⚠️ $PROJECT_2_NAME: no node_modules/.pnpm"
echo " Path: $PNPM_DIR_2"
else
echo "🔎 Looking for overlapping dependencies..."
PACKAGES_1=($(find "$PNPM_DIR_1" -maxdepth 1 -type d -name "*@*" 2>/dev/null | xargs -I {} basename {}))
PACKAGES_2=($(find "$PNPM_DIR_2" -maxdepth 1 -type d -name "*@*" 2>/dev/null | xargs -I {} basename {}))
COMMON_PACKAGES=()
for pkg1 in "${PACKAGES_1[@]}"; do
for pkg2 in "${PACKAGES_2[@]}"; do
if [ "$pkg1" = "$pkg2" ]; then
COMMON_PACKAGES+=("$pkg1")
break
fi
done
done
if [ ${#COMMON_PACKAGES[@]} -eq 0 ]; then
echo "⚠️ No shared packages between the two projects"
else
echo "📦 Found ${#COMMON_PACKAGES[@]} shared package(s); verifying..."
echo ""
VERIFIED_COUNT=0
SAME_INODE_COUNT=0
for pkg in "${COMMON_PACKAGES[@]:0:5}"; do
PKG_FILE_1=$(find "$PNPM_DIR_1/$pkg" -name "package.json" -path "*/node_modules/*/package.json" 2>/dev/null | head -n 1)
PKG_FILE_2=$(find "$PNPM_DIR_2/$pkg" -name "package.json" -path "*/node_modules/*/package.json" 2>/dev/null | head -n 1)
if [ -n "$PKG_FILE_1" ] && [ -f "$PKG_FILE_1" ] && [ -n "$PKG_FILE_2" ] && [ -f "$PKG_FILE_2" ]; then
INODE_1=$(ls -i "$PKG_FILE_1" | awk '{print $1}')
INODE_2=$(ls -i "$PKG_FILE_2" | awk '{print $1}')
PKG_DISPLAY=$(echo "$pkg" | sed 's/@[^@]*$//')
if [ "$INODE_1" = "$INODE_2" ]; then
echo "$PKG_DISPLAY: inode=$INODE_1 (same)"
((SAME_INODE_COUNT++))
else
echo "$PKG_DISPLAY: $INODE_1 vs $INODE_2 (different)"
fi
((VERIFIED_COUNT++))
fi
done
echo ""
echo "======================================"
if [ $VERIFIED_COUNT -eq 0 ]; then
echo "⚠️ Could not verify package files"
elif [ $SAME_INODE_COUNT -eq $VERIFIED_COUNT ]; then
echo "✅ Hard links look good"
echo " Checked $VERIFIED_COUNT package(s); all inodes match"
echo " Same physical files → disk savings from deduplication"
elif [ $SAME_INODE_COUNT -eq 0 ]; then
echo "❌ Hard links not shared"
echo " Checked $VERIFIED_COUNT package(s); inodes all differ"
echo ""
echo " Possible causes:"
echo " - Projects on different filesystems"
echo " - Filesystem without working hard links (e.g. some network mounts)"
echo " - pnpm / store configuration"
else
echo "⚠️ Mixed results"
echo " Checked $VERIFIED_COUNT package(s); $SAME_INODE_COUNT inode match(es)"
echo " May indicate inconsistent config or partial reinstalls"
fi
fi
fi
fi
fi
fi
echo ""
fi
fi
echo "✅ Done"