chore(scripts): add lint-infra, typecheck-all, test-all cross-repo scripts
This commit is contained in:
parent
f8c0da5c2a
commit
409144a2ef
11
AGENTS.md
11
AGENTS.md
@ -344,6 +344,17 @@ npx tsx scripts/encrypt-migrate.ts --product chronomind # Live encrypt
|
|||||||
./scripts/prep-consumer.sh /path/to/consumer-dir # pack + rewrite
|
./scripts/prep-consumer.sh /path/to/consumer-dir # pack + rewrite
|
||||||
./scripts/prep-consumer.sh /path/to/consumer-dir --restore # undo
|
./scripts/prep-consumer.sh /path/to/consumer-dir --restore # undo
|
||||||
|
|
||||||
|
# ── Infrastructure lint (Dockerfiles + Helm charts) ─
|
||||||
|
./scripts/lint-infra.sh # Lint all 25 Dockerfiles + any Helm charts
|
||||||
|
./scripts/lint-infra.sh --docker # Dockerfiles only
|
||||||
|
./scripts/lint-infra.sh --helm # Helm charts only
|
||||||
|
./scripts/lint-infra.sh path/to/Dockerfile # Explicit path(s)
|
||||||
|
# Requires: brew install hadolint helm
|
||||||
|
|
||||||
|
# ── Cross-repo typecheck + test ──────────────────────
|
||||||
|
./scripts/typecheck-all.sh # pnpm typecheck across all 11 repos
|
||||||
|
./scripts/test-all.sh # pnpm test --run across all 11 repos
|
||||||
|
|
||||||
# ── Health check all services ──────────────────────
|
# ── Health check all services ──────────────────────
|
||||||
pnpm --filter @lysnrai/monitoring check
|
pnpm --filter @lysnrai/monitoring check
|
||||||
```
|
```
|
||||||
|
|||||||
21
README.md
21
README.md
@ -159,6 +159,27 @@ Each consumer repo has a convenience wrapper: `scripts/docker-prep.sh` (or `scri
|
|||||||
|
|
||||||
> **Dashboards inside this repo** (`dashboards/admin-web`, `dashboards/tracker-web`) use `workspace:*` refs and do NOT need this workflow — pnpm resolves them automatically.
|
> **Dashboards inside this repo** (`dashboards/admin-web`, `dashboards/tracker-web`) use `workspace:*` refs and do NOT need this workflow — pnpm resolves them automatically.
|
||||||
|
|
||||||
|
## Infrastructure Lint
|
||||||
|
|
||||||
|
Validates all 25 Dockerfiles across the 11 ByteLyst repos using [hadolint](https://github.com/hadolint/hadolint), and any Helm charts using `helm lint` + `helm template`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Prerequisites
|
||||||
|
brew install hadolint helm
|
||||||
|
|
||||||
|
# Lint everything
|
||||||
|
./scripts/lint-infra.sh
|
||||||
|
|
||||||
|
# Dockerfiles only / Helm charts only
|
||||||
|
./scripts/lint-infra.sh --docker
|
||||||
|
./scripts/lint-infra.sh --helm
|
||||||
|
|
||||||
|
# Explicit paths
|
||||||
|
./scripts/lint-infra.sh path/to/Dockerfile path/to/chart-dir
|
||||||
|
```
|
||||||
|
|
||||||
|
Suppressed rules (false positives for this codebase): `DL3045`, `DL3018`, `DL3008`, `DL3059`, `SC2155`.
|
||||||
|
|
||||||
## Design Tokens
|
## Design Tokens
|
||||||
|
|
||||||
Generate platform-specific token files from the canonical JSON:
|
Generate platform-specific token files from the canonical JSON:
|
||||||
|
|||||||
348
scripts/lint-infra.sh
Executable file
348
scripts/lint-infra.sh
Executable file
@ -0,0 +1,348 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════
|
||||||
|
# lint-infra.sh — Infrastructure validation for the ByteLyst ecosystem
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════
|
||||||
|
# Validates all Dockerfiles (hadolint) and Helm charts (helm lint + template)
|
||||||
|
# across the 11 ByteLyst repos.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./scripts/lint-infra.sh # Lint everything (Dockerfiles + Helm charts)
|
||||||
|
# ./scripts/lint-infra.sh --docker # Dockerfiles only
|
||||||
|
# ./scripts/lint-infra.sh --helm # Helm charts only
|
||||||
|
# ./scripts/lint-infra.sh --fix # Show suggested fixes alongside errors
|
||||||
|
# ./scripts/lint-infra.sh path/to/Dockerfile [path/to/Chart-dir] ...
|
||||||
|
#
|
||||||
|
# Prerequisites:
|
||||||
|
# brew install hadolint helm
|
||||||
|
#
|
||||||
|
# Exit codes:
|
||||||
|
# 0 All checks passed
|
||||||
|
# 1 One or more checks failed
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ── Colors ─────────────────────────────────────────────────────────────
|
||||||
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
||||||
|
CYAN='\033[0;36m'; BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m'
|
||||||
|
|
||||||
|
# ── Globals ────────────────────────────────────────────────────────────
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
WORKSPACE_ROOT="$(cd "$REPO_ROOT/.." && pwd)"
|
||||||
|
|
||||||
|
LINT_DOCKER=true
|
||||||
|
LINT_HELM=true
|
||||||
|
SHOW_FIX=false
|
||||||
|
EXPLICIT_PATHS=()
|
||||||
|
|
||||||
|
PASS=0
|
||||||
|
FAIL=0
|
||||||
|
SKIP=0
|
||||||
|
FAILURES=()
|
||||||
|
|
||||||
|
# ── Known Hadolint false-positive suppressions ─────────────────────────
|
||||||
|
# DL3045: COPY to relative path — all our Dockerfiles set WORKDIR first
|
||||||
|
# DL3018: Pin versions in apk add — we use node:22-alpine base images
|
||||||
|
# DL3008: Pin versions in apt-get — impractical for Python sidecar base images
|
||||||
|
# DL3059: Multiple consecutive RUN — intentional for layer caching
|
||||||
|
# SC2155: Declare and assign separately — false positive for BuildKit secret mount pattern
|
||||||
|
# (export VAR="$(cat /run/secrets/...)" is the canonical Docker secret idiom)
|
||||||
|
HADOLINT_IGNORE="DL3045,DL3018,DL3008,DL3059,SC2155"
|
||||||
|
|
||||||
|
# ── ByteLyst ecosystem repos (relative to workspace root) ─────────────
|
||||||
|
ECOSYSTEM_REPOS=(
|
||||||
|
learning_ai_common_plat
|
||||||
|
learning_voice_ai_agent
|
||||||
|
learning_multimodal_memory_agents
|
||||||
|
learning_ai_clock
|
||||||
|
learning_ai_jarvis_jr
|
||||||
|
learning_ai_fastgap
|
||||||
|
learning_ai_peakpulse
|
||||||
|
learning_ai_flowmonk
|
||||||
|
learning_ai_notes
|
||||||
|
learning_ai_trails
|
||||||
|
learning_ai_local_memory_gpt
|
||||||
|
)
|
||||||
|
|
||||||
|
# ── Helpers ────────────────────────────────────────────────────────────
|
||||||
|
log() { echo -e "${CYAN}[lint-infra]${NC} $*"; }
|
||||||
|
ok() { echo -e " ${GREEN}✓${NC} $*"; PASS=$((PASS + 1)); }
|
||||||
|
fail() { echo -e " ${RED}✗${NC} $*"; FAIL=$((FAIL + 1)); FAILURES+=("$1"); }
|
||||||
|
skip() { echo -e " ${DIM}⊘ $*${NC}"; SKIP=$((SKIP + 1)); }
|
||||||
|
warn() { echo -e " ${YELLOW}⚠${NC} $*"; }
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $(basename "$0") [OPTIONS] [PATH ...]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " --docker Lint Dockerfiles only"
|
||||||
|
echo " --helm Lint Helm charts only"
|
||||||
|
echo " --fix Show suggested fixes alongside errors"
|
||||||
|
echo " -h, --help Show this help"
|
||||||
|
echo ""
|
||||||
|
echo "If PATHs are given, only those files/dirs are checked."
|
||||||
|
echo "Otherwise, auto-discovers across all 11 ByteLyst repos."
|
||||||
|
echo ""
|
||||||
|
echo "Prerequisites: brew install hadolint helm"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if a tool is available, print install instructions if not
|
||||||
|
require_tool() {
|
||||||
|
local tool="$1" install_cmd="$2"
|
||||||
|
if ! command -v "$tool" &>/dev/null; then
|
||||||
|
echo -e "${RED}Error:${NC} '${tool}' is not installed."
|
||||||
|
echo -e " Install: ${BOLD}${install_cmd}${NC}"
|
||||||
|
echo ""
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Return a short relative path for display
|
||||||
|
short_path() {
|
||||||
|
local full="$1"
|
||||||
|
# Try to make path relative to workspace root
|
||||||
|
if [[ "$full" == "$WORKSPACE_ROOT"/* ]]; then
|
||||||
|
echo "${full#$WORKSPACE_ROOT/}"
|
||||||
|
else
|
||||||
|
echo "$full"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Auto-discovery ─────────────────────────────────────────────────────
|
||||||
|
discover_dockerfiles() {
|
||||||
|
local files=()
|
||||||
|
for repo in "${ECOSYSTEM_REPOS[@]}"; do
|
||||||
|
local repo_dir="${WORKSPACE_ROOT}/${repo}"
|
||||||
|
[ -d "$repo_dir" ] || continue
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
files+=("$f")
|
||||||
|
done < <(find "$repo_dir" -maxdepth 4 -name 'Dockerfile*' \
|
||||||
|
-not -path '*/node_modules/*' \
|
||||||
|
-not -path '*/.git/*' \
|
||||||
|
-not -path '*/_deferred*' \
|
||||||
|
-print0 2>/dev/null | sort -z)
|
||||||
|
done
|
||||||
|
echo "${files[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
discover_helm_charts() {
|
||||||
|
local dirs=()
|
||||||
|
for repo in "${ECOSYSTEM_REPOS[@]}"; do
|
||||||
|
local repo_dir="${WORKSPACE_ROOT}/${repo}"
|
||||||
|
[ -d "$repo_dir" ] || continue
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
dirs+=("$(dirname "$f")")
|
||||||
|
done < <(find "$repo_dir" -maxdepth 4 -name 'Chart.yaml' \
|
||||||
|
-not -path '*/node_modules/*' \
|
||||||
|
-not -path '*/.git/*' \
|
||||||
|
-print0 2>/dev/null | sort -z)
|
||||||
|
done
|
||||||
|
echo "${dirs[@]+"${dirs[@]}"}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Lint functions ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
lint_dockerfile() {
|
||||||
|
local file="$1"
|
||||||
|
local display
|
||||||
|
display=$(short_path "$file")
|
||||||
|
|
||||||
|
if [ ! -f "$file" ]; then
|
||||||
|
skip "${display} (not found)"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local output exit_code=0
|
||||||
|
# Build hadolint args
|
||||||
|
local hadolint_args=(--no-color)
|
||||||
|
IFS=',' read -ra ignore_rules <<< "$HADOLINT_IGNORE"
|
||||||
|
for rule in "${ignore_rules[@]}"; do
|
||||||
|
hadolint_args+=(--ignore "$rule")
|
||||||
|
done
|
||||||
|
|
||||||
|
output=$(hadolint "${hadolint_args[@]}" "$file" 2>&1) || exit_code=$?
|
||||||
|
|
||||||
|
if [ $exit_code -eq 0 ]; then
|
||||||
|
ok "${display}"
|
||||||
|
else
|
||||||
|
fail "${display}"
|
||||||
|
# Print each warning/error indented
|
||||||
|
while IFS= read -r line; do
|
||||||
|
if [[ "$line" == *"error"* ]]; then
|
||||||
|
echo -e " ${RED}${line}${NC}"
|
||||||
|
elif [[ "$line" == *"warning"* ]]; then
|
||||||
|
echo -e " ${YELLOW}${line}${NC}"
|
||||||
|
else
|
||||||
|
echo -e " ${DIM}${line}${NC}"
|
||||||
|
fi
|
||||||
|
done <<< "$output"
|
||||||
|
|
||||||
|
if $SHOW_FIX; then
|
||||||
|
echo -e " ${CYAN}Fix: review hadolint wiki — https://github.com/hadolint/hadolint/wiki${NC}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
lint_helm_chart() {
|
||||||
|
local chart_dir="$1"
|
||||||
|
local display
|
||||||
|
display=$(short_path "$chart_dir")
|
||||||
|
|
||||||
|
if [ ! -f "${chart_dir}/Chart.yaml" ]; then
|
||||||
|
skip "${display} (no Chart.yaml)"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local output exit_code
|
||||||
|
|
||||||
|
# 1. helm lint (syntax + structure)
|
||||||
|
output=$(helm lint "$chart_dir" 2>&1) || exit_code=$?
|
||||||
|
if [ "${exit_code:-0}" -ne 0 ]; then
|
||||||
|
fail "${display} (helm lint)"
|
||||||
|
echo "$output" | while IFS= read -r line; do
|
||||||
|
echo -e " ${DIM}${line}${NC}"
|
||||||
|
done
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. helm template (renders without errors)
|
||||||
|
output=$(helm template test-release "$chart_dir" 2>&1) || exit_code=$?
|
||||||
|
if [ "${exit_code:-0}" -ne 0 ]; then
|
||||||
|
fail "${display} (helm template)"
|
||||||
|
echo "$output" | tail -10 | while IFS= read -r line; do
|
||||||
|
echo -e " ${DIM}${line}${NC}"
|
||||||
|
done
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
ok "${display}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Parse CLI ──────────────────────────────────────────────────────────
|
||||||
|
parse_args() {
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--docker)
|
||||||
|
LINT_DOCKER=true; LINT_HELM=false ;;
|
||||||
|
--helm)
|
||||||
|
LINT_DOCKER=false; LINT_HELM=true ;;
|
||||||
|
--fix)
|
||||||
|
SHOW_FIX=true ;;
|
||||||
|
-h|--help)
|
||||||
|
usage; exit 0 ;;
|
||||||
|
-*)
|
||||||
|
echo "Unknown option: $1"; usage; exit 1 ;;
|
||||||
|
*)
|
||||||
|
EXPLICIT_PATHS+=("$1") ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Main ───────────────────────────────────────────────────────────────
|
||||||
|
main() {
|
||||||
|
parse_args "$@"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${BOLD}╔═══════════════════════════════════════════════════════════╗${NC}"
|
||||||
|
echo -e "${BOLD}║ ByteLyst Infrastructure Lint ║${NC}"
|
||||||
|
echo -e "${BOLD}╚═══════════════════════════════════════════════════════════╝${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ── Tool checks ────────────────────────────────────────────────────
|
||||||
|
local missing=false
|
||||||
|
if $LINT_DOCKER; then
|
||||||
|
require_tool hadolint "brew install hadolint" || missing=true
|
||||||
|
fi
|
||||||
|
if $LINT_HELM; then
|
||||||
|
require_tool helm "brew install helm" || missing=true
|
||||||
|
fi
|
||||||
|
if $missing; then
|
||||||
|
echo -e "${RED}Missing required tools. Install them and re-run.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Explicit paths mode ────────────────────────────────────────────
|
||||||
|
if [ ${#EXPLICIT_PATHS[@]} -gt 0 ]; then
|
||||||
|
log "Linting ${#EXPLICIT_PATHS[@]} explicit path(s)..."
|
||||||
|
echo ""
|
||||||
|
for p in "${EXPLICIT_PATHS[@]}"; do
|
||||||
|
if [[ "$(basename "$p")" == Dockerfile* ]]; then
|
||||||
|
lint_dockerfile "$p"
|
||||||
|
elif [ -f "${p}/Chart.yaml" ]; then
|
||||||
|
lint_helm_chart "$p"
|
||||||
|
else
|
||||||
|
warn "Unknown target: $p (expected Dockerfile* or dir with Chart.yaml)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# ── Auto-discover mode ─────────────────────────────────────────
|
||||||
|
if $LINT_DOCKER; then
|
||||||
|
log "Discovering Dockerfiles across ${#ECOSYSTEM_REPOS[@]} repos..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
local dockerfiles
|
||||||
|
IFS=' ' read -ra dockerfiles <<< "$(discover_dockerfiles)"
|
||||||
|
|
||||||
|
if [ ${#dockerfiles[@]} -eq 0 ]; then
|
||||||
|
warn "No Dockerfiles found."
|
||||||
|
else
|
||||||
|
log "Found ${#dockerfiles[@]} Dockerfile(s)"
|
||||||
|
echo ""
|
||||||
|
for df in "${dockerfiles[@]}"; do
|
||||||
|
lint_dockerfile "$df"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $LINT_HELM; then
|
||||||
|
log "Discovering Helm charts across ${#ECOSYSTEM_REPOS[@]} repos..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
local charts
|
||||||
|
IFS=' ' read -ra charts <<< "$(discover_helm_charts)"
|
||||||
|
|
||||||
|
if [ ${#charts[@]} -eq 0 ] || [ -z "${charts[0]:-}" ]; then
|
||||||
|
log "No Helm charts found (none in this workspace)."
|
||||||
|
else
|
||||||
|
log "Found ${#charts[@]} Helm chart(s)"
|
||||||
|
echo ""
|
||||||
|
for chart in "${charts[@]}"; do
|
||||||
|
lint_helm_chart "$chart"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Summary ──────────────────────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo -e "${BOLD}═══ Summary ═══${NC}"
|
||||||
|
echo -e " ${GREEN}Passed:${NC} ${PASS}"
|
||||||
|
echo -e " ${RED}Failed:${NC} ${FAIL}"
|
||||||
|
if [ $SKIP -gt 0 ]; then
|
||||||
|
echo -e " ${DIM}Skipped: ${SKIP}${NC}"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ $FAIL -gt 0 ]; then
|
||||||
|
echo -e "${RED}${BOLD}FAILED${NC} — ${FAIL} issue(s) found:"
|
||||||
|
for f in "${FAILURES[@]}"; do
|
||||||
|
echo -e " ${RED}✗${NC} ${f}"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
echo -e "${DIM}Suppressed rules: ${HADOLINT_IGNORE}${NC}"
|
||||||
|
echo -e "${DIM}To see fix suggestions, re-run with --fix${NC}"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}${BOLD}ALL PASSED${NC} — ${PASS} check(s) clean."
|
||||||
|
if [ $SKIP -gt 0 ]; then
|
||||||
|
echo -e "${DIM}(${SKIP} skipped)${NC}"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
95
scripts/test-all.sh
Executable file
95
scripts/test-all.sh
Executable file
@ -0,0 +1,95 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════
|
||||||
|
# test-all.sh — Run Vitest across all ByteLyst repos
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
RED='\033[0;31m'; GREEN='\033[0;32m'; CYAN='\033[0;36m'
|
||||||
|
BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m'
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
WORKSPACE_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
|
||||||
|
PASS=0
|
||||||
|
FAIL=0
|
||||||
|
SKIP=0
|
||||||
|
FAILURES=()
|
||||||
|
|
||||||
|
REPOS=(
|
||||||
|
learning_ai_common_plat
|
||||||
|
learning_voice_ai_agent
|
||||||
|
learning_multimodal_memory_agents
|
||||||
|
learning_ai_clock
|
||||||
|
learning_ai_jarvis_jr
|
||||||
|
learning_ai_fastgap
|
||||||
|
learning_ai_peakpulse
|
||||||
|
learning_ai_flowmonk
|
||||||
|
learning_ai_notes
|
||||||
|
learning_ai_trails
|
||||||
|
learning_ai_local_memory_gpt
|
||||||
|
)
|
||||||
|
|
||||||
|
SUBS=(backend web user-dashboard-web mindlyst-native/web)
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${BOLD}╔═══════════════════════════════════════════════════════════╗${NC}"
|
||||||
|
echo -e "${BOLD}║ ByteLyst Cross-Repo Test Runner ║${NC}"
|
||||||
|
echo -e "${BOLD}╚═══════════════════════════════════════════════════════════╝${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
for repo in "${REPOS[@]}"; do
|
||||||
|
repo_dir="${WORKSPACE_ROOT}/${repo}"
|
||||||
|
[ -d "$repo_dir" ] || continue
|
||||||
|
|
||||||
|
for sub in "${SUBS[@]}"; do
|
||||||
|
pkg="${repo_dir}/${sub}/package.json"
|
||||||
|
[ -f "$pkg" ] || continue
|
||||||
|
|
||||||
|
has_test=$(jq -r '.scripts.test // empty' "$pkg" 2>/dev/null)
|
||||||
|
[ -n "$has_test" ] || continue
|
||||||
|
|
||||||
|
# Check if there are actually test files
|
||||||
|
test_count=$(find "${repo_dir}/${sub}/src" -name '*.test.ts' -o -name '*.test.tsx' 2>/dev/null | head -1)
|
||||||
|
if [ -z "$test_count" ]; then
|
||||||
|
SKIP=$((SKIP + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
label="${repo}/${sub}"
|
||||||
|
echo -ne " ${CYAN}▶${NC} ${label}..."
|
||||||
|
|
||||||
|
if (cd "${repo_dir}/${sub}" && pnpm run test --run 2>&1) > /tmp/test-output-$$.txt 2>&1; then
|
||||||
|
# Extract test count from vitest output
|
||||||
|
summary=$(grep -E 'Tests\s+[0-9]' /tmp/test-output-$$.txt 2>/dev/null | tail -1 || echo "")
|
||||||
|
echo -e "\r ${GREEN}✓${NC} ${label} ${DIM}${summary}${NC}"
|
||||||
|
PASS=$((PASS + 1))
|
||||||
|
else
|
||||||
|
echo -e "\r ${RED}✗${NC} ${label}"
|
||||||
|
grep -E 'FAIL|Error|failed' /tmp/test-output-$$.txt 2>/dev/null | tail -5 | while IFS= read -r line; do echo " ${line}"; done
|
||||||
|
FAIL=$((FAIL + 1))
|
||||||
|
FAILURES+=("$label")
|
||||||
|
fi
|
||||||
|
rm -f /tmp/test-output-$$.txt
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${BOLD}═══ Summary ═══${NC}"
|
||||||
|
echo -e " ${GREEN}Passed:${NC} ${PASS}"
|
||||||
|
echo -e " ${RED}Failed:${NC} ${FAIL}"
|
||||||
|
if [ $SKIP -gt 0 ]; then
|
||||||
|
echo -e " ${DIM}Skipped: ${SKIP} (no test files)${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $FAIL -gt 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo -e "${RED}${BOLD}FAILED${NC} — ${FAIL} test suite(s) failed:"
|
||||||
|
for f in "${FAILURES[@]}"; do
|
||||||
|
echo -e " ${RED}✗${NC} ${f}"
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}${BOLD}ALL PASSED${NC} — ${PASS} suite(s) green."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
83
scripts/typecheck-all.sh
Executable file
83
scripts/typecheck-all.sh
Executable file
@ -0,0 +1,83 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════
|
||||||
|
# typecheck-all.sh — Run TypeScript typecheck across all ByteLyst repos
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
RED='\033[0;31m'; GREEN='\033[0;32m'; CYAN='\033[0;36m'
|
||||||
|
BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m'
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
WORKSPACE_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
|
||||||
|
PASS=0
|
||||||
|
FAIL=0
|
||||||
|
FAILURES=()
|
||||||
|
|
||||||
|
REPOS=(
|
||||||
|
learning_ai_common_plat
|
||||||
|
learning_voice_ai_agent
|
||||||
|
learning_multimodal_memory_agents
|
||||||
|
learning_ai_clock
|
||||||
|
learning_ai_jarvis_jr
|
||||||
|
learning_ai_fastgap
|
||||||
|
learning_ai_peakpulse
|
||||||
|
learning_ai_flowmonk
|
||||||
|
learning_ai_notes
|
||||||
|
learning_ai_trails
|
||||||
|
learning_ai_local_memory_gpt
|
||||||
|
)
|
||||||
|
|
||||||
|
# Subdirectories that may have their own typecheck script
|
||||||
|
SUBS=(backend web user-dashboard-web mindlyst-native/web)
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${BOLD}╔═══════════════════════════════════════════════════════════╗${NC}"
|
||||||
|
echo -e "${BOLD}║ ByteLyst Cross-Repo Typecheck ║${NC}"
|
||||||
|
echo -e "${BOLD}╚═══════════════════════════════════════════════════════════╝${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
for repo in "${REPOS[@]}"; do
|
||||||
|
repo_dir="${WORKSPACE_ROOT}/${repo}"
|
||||||
|
[ -d "$repo_dir" ] || continue
|
||||||
|
|
||||||
|
for sub in "${SUBS[@]}"; do
|
||||||
|
pkg="${repo_dir}/${sub}/package.json"
|
||||||
|
[ -f "$pkg" ] || continue
|
||||||
|
|
||||||
|
has_tc=$(jq -r '.scripts.typecheck // empty' "$pkg" 2>/dev/null)
|
||||||
|
[ -n "$has_tc" ] || continue
|
||||||
|
|
||||||
|
label="${repo}/${sub}"
|
||||||
|
echo -ne " ${CYAN}▶${NC} ${label}..."
|
||||||
|
|
||||||
|
if (cd "${repo_dir}/${sub}" && pnpm run typecheck 2>&1) > /tmp/tc-output-$$.txt 2>&1; then
|
||||||
|
echo -e "\r ${GREEN}✓${NC} ${label}"
|
||||||
|
PASS=$((PASS + 1))
|
||||||
|
else
|
||||||
|
echo -e "\r ${RED}✗${NC} ${label}"
|
||||||
|
tail -5 /tmp/tc-output-$$.txt | while IFS= read -r line; do echo " ${line}"; done
|
||||||
|
FAIL=$((FAIL + 1))
|
||||||
|
FAILURES+=("$label")
|
||||||
|
fi
|
||||||
|
rm -f /tmp/tc-output-$$.txt
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${BOLD}═══ Summary ═══${NC}"
|
||||||
|
echo -e " ${GREEN}Passed:${NC} ${PASS}"
|
||||||
|
echo -e " ${RED}Failed:${NC} ${FAIL}"
|
||||||
|
|
||||||
|
if [ $FAIL -gt 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo -e "${RED}${BOLD}FAILED${NC} — ${FAIL} typecheck(s) failed:"
|
||||||
|
for f in "${FAILURES[@]}"; do
|
||||||
|
echo -e " ${RED}✗${NC} ${f}"
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}${BOLD}ALL PASSED${NC} — ${PASS} typecheck(s) clean."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
Loading…
Reference in New Issue
Block a user