ci: update CI/CD configuration

This commit is contained in:
saravanakumardb1 2026-04-12 23:45:30 -07:00
parent a7679de295
commit 9db3967fe1
13 changed files with 488 additions and 227 deletions

View File

@ -1,9 +1,9 @@
Last refresh: 2026-04-03T06:28:08Z (2026-04-02 23:28:08 PDT)
Cascade conversations: 50 (298M)
Memories: 121
Last refresh: 2026-04-13T06:13:49Z (2026-04-12 23:13:49 PDT)
Cascade conversations: 50 (421M)
Memories: 130
Implicit context: 20
Code tracker dirs: 103
File edit history: 4225 entries
Workspace storage: 37 workspaces
Code tracker dirs: 108
File edit history: 4591 entries
Workspace storage: 41 workspaces
Repo docs: 7 files across 2 repos
Repo workflows: 54 files across 12 repos
Repo workflows: 55 files across 12 repos

View File

@ -9,17 +9,17 @@
## 1. Project → Env File Map
| # | Project | Env File | Port |
|---|---------|----------|------|
| 1 | Desktop app (`src/`) | `.env` (root) | — |
| 2 | Backend API (`backend/`) | `backend/.env` | 8000 |
| 3 | Admin Dashboard (`admin-dashboard-web/`) | `admin-dashboard-web/.env.local` | 3001 |
| 4 | User Dashboard (`user-dashboard-web/`) | `user-dashboard-web/.env.local` | 3002 |
| 5 | Tracker Dashboard (`tracker-dashboard-web/`) | `tracker-dashboard-web/.env.local` | 3003 |
| 6 | Billing Service (`services/billing-service/`) | `services/billing-service/.env` | 4002 |
| 7 | Growth Service (`services/growth-service/`) | `services/growth-service/.env` | 4001 |
| 8 | Platform Service (`services/platform-service/`) | `services/platform-service/.env` | 4003 |
| 9 | Tracker Service (`services/tracker-service/`) | `services/tracker-service/.env` | 4004 |
| # | Project | Env File | Port |
| --- | ----------------------------------------------- | ---------------------------------- | ---- |
| 1 | Desktop app (`src/`) | `.env` (root) | — |
| 2 | Backend API (`backend/`) | `backend/.env` | 8000 |
| 3 | Admin Dashboard (`admin-dashboard-web/`) | `admin-dashboard-web/.env.local` | 3001 |
| 4 | User Dashboard (`user-dashboard-web/`) | `user-dashboard-web/.env.local` | 3002 |
| 5 | Tracker Dashboard (`tracker-dashboard-web/`) | `tracker-dashboard-web/.env.local` | 3003 |
| 6 | Billing Service (`services/billing-service/`) | `services/billing-service/.env` | 4002 |
| 7 | Growth Service (`services/growth-service/`) | `services/growth-service/.env` | 4001 |
| 8 | Platform Service (`services/platform-service/`) | `services/platform-service/.env` | 4003 |
| 9 | Tracker Service (`services/tracker-service/`) | `services/tracker-service/.env` | 4004 |
---
@ -36,63 +36,63 @@ grep -rn 'MISSING_ENV_VALUE' --include='.env*' --include='*.env' . | grep -v nod
### 3.1 Root `.env` (Desktop App)
| Variable | Status | Action |
|----------|--------|--------|
| `APPLICATIONINSIGHTS_CONNECTION_STRING` | ❌ Empty | Get from Azure Portal → Application Insights → Overview |
| `ANH_CONNECTION_STRING` | ⚠️ Has `YOUR_KEY_HERE` placeholder | Replace with real SharedAccessKey from Azure Portal → Notification Hubs |
| Variable | Status | Action |
| --------------------------------------- | ---------------------------------- | ----------------------------------------------------------------------- |
| `APPLICATIONINSIGHTS_CONNECTION_STRING` | ❌ Empty | Get from Azure Portal → Application Insights → Overview |
| `ANH_CONNECTION_STRING` | ⚠️ Has `YOUR_KEY_HERE` placeholder | Replace with real SharedAccessKey from Azure Portal → Notification Hubs |
### 3.2 `backend/.env`
| Variable | Status | Action |
|----------|--------|--------|
| `AZURE_EMAIL_CONNECTION_STRING` | ❌ Empty | Get from Azure Portal → Communication Services → Keys |
| `SMTP_HOST` | ❌ Empty | Configure if using SMTP fallback instead of Azure Communication Services |
| `SMTP_USER` | ❌ Empty | Configure if using SMTP fallback |
| `SMTP_PASS` | ❌ Empty | Configure if using SMTP fallback |
| Variable | Status | Action |
| ------------------------------- | -------- | ------------------------------------------------------------------------ |
| `AZURE_EMAIL_CONNECTION_STRING` | ❌ Empty | Get from Azure Portal → Communication Services → Keys |
| `SMTP_HOST` | ❌ Empty | Configure if using SMTP fallback instead of Azure Communication Services |
| `SMTP_USER` | ❌ Empty | Configure if using SMTP fallback |
| `SMTP_PASS` | ❌ Empty | Configure if using SMTP fallback |
### 3.3 `admin-dashboard-web/.env.local`
| Variable | Status | Action |
|----------|--------|--------|
| `NEXT_PUBLIC_POSTHOG_KEY` | ❌ Empty | Get from PostHog → Project Settings (optional — analytics) |
| Variable | Status | Action |
| -------------------------- | -------- | ---------------------------------------------------------- |
| `NEXT_PUBLIC_POSTHOG_KEY` | ❌ Empty | Get from PostHog → Project Settings (optional — analytics) |
| `NEXT_PUBLIC_POSTHOG_HOST` | ❌ Empty | Get from PostHog → Project Settings (optional — analytics) |
### 3.4 `user-dashboard-web/.env.local`
| Variable | Status | Action |
|----------|--------|--------|
| Variable | Status | Action |
| -------------------------- | -------- | ------------------------------------------------------------------- |
| `ENTERPRISE_EMAIL_DOMAINS` | ❌ Empty | Set comma-separated list of domains that qualify for Enterprise SSO |
| `MICROSOFT_CLIENT_ID` | ❌ Empty | Register app in Azure Portal → Entra ID → App registrations |
| `MICROSOFT_CLIENT_SECRET` | ❌ Empty | Same as above |
| `GOOGLE_CLIENT_ID` | ❌ Empty | Register app in Google Cloud Console → Credentials |
| `GOOGLE_CLIENT_SECRET` | ❌ Empty | Same as above |
| `NEXT_PUBLIC_POSTHOG_KEY` | ❌ Empty | PostHog analytics (optional) |
| `NEXT_PUBLIC_POSTHOG_HOST` | ❌ Empty | PostHog analytics (optional) |
| `MICROSOFT_CLIENT_ID` | ❌ Empty | Register app in Azure Portal → Entra ID → App registrations |
| `MICROSOFT_CLIENT_SECRET` | ❌ Empty | Same as above |
| `GOOGLE_CLIENT_ID` | ❌ Empty | Register app in Google Cloud Console → Credentials |
| `GOOGLE_CLIENT_SECRET` | ❌ Empty | Same as above |
| `NEXT_PUBLIC_POSTHOG_KEY` | ❌ Empty | PostHog analytics (optional) |
| `NEXT_PUBLIC_POSTHOG_HOST` | ❌ Empty | PostHog analytics (optional) |
### 3.5 `tracker-dashboard-web/.env.local`
| Variable | Status | Action |
|----------|--------|--------|
| `NEXT_PUBLIC_POSTHOG_KEY` | ❌ Empty | PostHog analytics (optional) |
| Variable | Status | Action |
| -------------------------- | -------- | ---------------------------- |
| `NEXT_PUBLIC_POSTHOG_KEY` | ❌ Empty | PostHog analytics (optional) |
| `NEXT_PUBLIC_POSTHOG_HOST` | ❌ Empty | PostHog analytics (optional) |
### 3.6 `services/growth-service/.env`
| Variable | Status | Action |
|----------|--------|--------|
| Variable | Status | Action |
| --------------------------------- | -------- | ------------------------------------------------------------ |
| `WEBHOOK_INVITATION_REDEEMED_URL` | ❌ Empty | Set to backend or platform-service webhook callback endpoint |
| `WEBHOOK_REFERRAL_STATUS_URL` | ❌ Empty | Set to backend or platform-service webhook callback endpoint |
| `WEBHOOK_REFERRAL_STATUS_URL` | ❌ Empty | Set to backend or platform-service webhook callback endpoint |
### 3.7 `services/billing-service/.env`
| Variable | Status | Action |
|----------|--------|--------|
| Variable | Status | Action |
| ------------------ | -------- | --------------------------------------------------------------- |
| `PLAN_LIMITS_JSON` | ❌ Empty | Optional — set JSON with per-plan limits if overriding defaults |
### 3.8 `services/platform-service/.env`
| Variable | Status | Action |
|----------|--------|--------|
| Variable | Status | Action |
| ------------------------ | -------- | ------------------------------------------------------------------------ |
| `RATE_LIMIT_CONFIG_JSON` | ❌ Empty | Optional — set JSON with per-endpoint rate limits if overriding defaults |
### 3.9 `services/tracker-service/.env`
@ -105,21 +105,21 @@ grep -rn 'MISSING_ENV_VALUE' --include='.env*' --include='*.env' . | grep -v nod
These were missing from `.env` files but had known values, so they were filled in:
| Project | Variable | Value Added |
|---------|----------|-------------|
| Root `.env` | `PLATFORM_SERVICE_URL` | `http://localhost:4003` |
| Root `.env` | `LYSNR_API_URL` | `http://localhost:8000` |
| Root `.env` | `LYSNR_ADMIN_URL` | `http://localhost:3001` |
| Root `.env` | `LYSNR_DASHBOARD_URL` | `http://localhost:3002` |
| `backend/.env` | `BILLING_SERVICE_URL` | `http://localhost:4002` |
| `backend/.env` | `PLATFORM_SERVICE_URL` | `http://localhost:4003` |
| `backend/.env` | `CORS_ORIGINS` | Expanded to include all dashboard ports |
| `admin-dashboard-web/.env.local` | `STRIPE_PUBLISHABLE_KEY` | Test key (was missing) |
| `admin-dashboard-web/.env.local` | `STRIPE_WEBHOOK_SECRET` | Test key (was missing) |
| `admin-dashboard-web/.env.local` | `STRIPE_PRICE_PRO` | `price_1Szl2z...` |
| `admin-dashboard-web/.env.local` | `STRIPE_PRICE_ENTERPRISE` | `price_1Szl3D...` |
| `user-dashboard-web/.env.local` | `ENTERPRISE_EMAIL_DOMAINS` | Empty (needs config) |
| `services/billing-service/.env` | `USAGE_WARN_THRESHOLD` | `80` |
| Project | Variable | Value Added |
| -------------------------------- | -------------------------- | --------------------------------------- |
| Root `.env` | `PLATFORM_SERVICE_URL` | `http://localhost:4003` |
| Root `.env` | `LYSNR_API_URL` | `http://localhost:8000` |
| Root `.env` | `LYSNR_ADMIN_URL` | `http://localhost:3001` |
| Root `.env` | `LYSNR_DASHBOARD_URL` | `http://localhost:3002` |
| `backend/.env` | `BILLING_SERVICE_URL` | `http://localhost:4002` |
| `backend/.env` | `PLATFORM_SERVICE_URL` | `http://localhost:4003` |
| `backend/.env` | `CORS_ORIGINS` | Expanded to include all dashboard ports |
| `admin-dashboard-web/.env.local` | `STRIPE_PUBLISHABLE_KEY` | Test key (was missing) |
| `admin-dashboard-web/.env.local` | `STRIPE_WEBHOOK_SECRET` | Test key (was missing) |
| `admin-dashboard-web/.env.local` | `STRIPE_PRICE_PRO` | `price_1Szl2z...` |
| `admin-dashboard-web/.env.local` | `STRIPE_PRICE_ENTERPRISE` | `price_1Szl3D...` |
| `user-dashboard-web/.env.local` | `ENTERPRISE_EMAIL_DOMAINS` | Empty (needs config) |
| `services/billing-service/.env` | `USAGE_WARN_THRESHOLD` | `80` |
---
@ -134,24 +134,27 @@ These were missing from `.env` files but had known values, so they were filled i
These values **must be identical** across all services that use them:
| Secret | Used By |
|--------|---------|
| `JWT_SECRET` | All 4 Fastify services + all 3 dashboards + backend |
| `COSMOS_ENDPOINT` | All 4 Fastify services + admin + user dashboards + backend + desktop |
| `COSMOS_KEY` | Same as above |
| `COSMOS_DATABASE` | Same as above (must be `lysnrai`) |
| `STRIPE_SECRET_KEY` | billing-service, growth-service, admin-dashboard, user-dashboard |
| `AZURE_BLOB_*` | platform-service, admin-dashboard, user-dashboard, desktop |
| Secret | Used By |
| ------------------- | -------------------------------------------------------------------- |
| `JWT_SECRET` | All 4 Fastify services + all 3 dashboards + backend |
| `COSMOS_ENDPOINT` | All 4 Fastify services + admin + user dashboards + backend + desktop |
| `COSMOS_KEY` | Same as above |
| `COSMOS_DATABASE` | Same as above (must be `lysnrai`) |
| `STRIPE_SECRET_KEY` | billing-service, growth-service, admin-dashboard, user-dashboard |
| `AZURE_BLOB_*` | platform-service, admin-dashboard, user-dashboard, desktop |
---
## 7. Production Deployment Notes
When deploying to **Vercel** (frontends) + **Railway** (backends):
When deploying to the current stack:
- **Vercel** for public/front-end surfaces where applicable
- **Azure VM / shared infra** for backend and internal service hosting
1. **JWT_SECRET** — rotate to a new 64-char hex. Must match across ALL services.
2. **CORS_ORIGIN** — set on each Fastify service to restrict to Vercel domains (comma-separated).
3. **Stripe webhook** — create a new webhook in Stripe Dashboard pointing to production URL; update `STRIPE_WEBHOOK_SECRET`.
4. **SSO redirect URIs** — update `MICROSOFT_REDIRECT_URI` and `GOOGLE_REDIRECT_URI` to production Vercel domain.
5. **NEXTAUTH_URL** — set to production Vercel domain for user-dashboard.
6. **Service URLs** — replace all `localhost:*` with Railway public URLs.
6. **Service URLs** — replace all `localhost:*` with the current production API and service URLs.

View File

@ -15,20 +15,12 @@ Systematically verify consistency across all ByteLyst product repos. Catches dri
```bash
REPOS_DIR="/Users/sd9235/code/mygh"
echo "=== packageManager in root package.json ==="
for repo in \
learning_ai_common_plat \
learning_voice_ai_agent \
learning_ai_clock \
learning_ai_fastgap \
learning_ai_jarvis_jr \
learning_ai_peakpulse \
learning_ai_notes \
learning_ai_flowmonk \
learning_ai_trails \
learning_ai_local_memory_gpt; do
while IFS= read -r repo; do
[[ -z "$repo" || "$repo" =~ ^# ]] && continue
[[ ! -f "$REPOS_DIR/$repo/package.json" ]] && continue
printf "%-40s " "$repo:"
grep '"packageManager"' "$REPOS_DIR/$repo/package.json" 2>/dev/null || echo "MISSING"
done
done < /Users/sd9235/code/mygh/learning_ai_common_plat/.windsurf/workflows/repos.txt
```
Expect: all repos show `"packageManager": "pnpm@10.6.5"`. Fix any MISSING entries.
@ -40,20 +32,12 @@ Expect: all repos show `"packageManager": "pnpm@10.6.5"`. Fix any MISSING entrie
```bash
REPOS_DIR="/Users/sd9235/code/mygh"
echo "=== node_modules in .gitignore ==="
for repo in \
learning_ai_common_plat \
learning_voice_ai_agent \
learning_ai_clock \
learning_ai_fastgap \
learning_ai_jarvis_jr \
learning_ai_peakpulse \
learning_ai_notes \
learning_ai_flowmonk \
learning_ai_trails \
learning_ai_local_memory_gpt; do
while IFS= read -r repo; do
[[ -z "$repo" || "$repo" =~ ^# ]] && continue
[[ ! -f "$REPOS_DIR/$repo/.gitignore" ]] && continue
printf "%-40s " "$repo:"
grep -c 'node_modules' "$REPOS_DIR/$repo/.gitignore" 2>/dev/null || echo "MISSING"
done
done < /Users/sd9235/code/mygh/learning_ai_common_plat/.windsurf/workflows/repos.txt
```
Expect: all repos have at least 1 match. Fix any with 0 or MISSING.
@ -65,16 +49,8 @@ Expect: all repos have at least 1 match. Fix any with 0 or MISSING.
```bash
REPOS_DIR="/Users/sd9235/code/mygh"
echo "=== .dockerignore health ==="
for repo in \
learning_voice_ai_agent \
learning_ai_clock \
learning_ai_fastgap \
learning_ai_jarvis_jr \
learning_ai_peakpulse \
learning_ai_notes \
learning_ai_flowmonk \
learning_ai_trails \
learning_ai_local_memory_gpt; do
while IFS= read -r repo; do
[[ -z "$repo" || "$repo" =~ ^# ]] && continue
di="$REPOS_DIR/$repo/.dockerignore"
if [ ! -f "$di" ]; then
echo "$repo: MISSING .dockerignore"
@ -83,10 +59,10 @@ for repo in \
else
echo "$repo: OK"
fi
done
done < /Users/sd9235/code/mygh/learning_ai_common_plat/.windsurf/workflows/repos.txt
```
Expect: all OK. Any BUG entries will break Docker builds.
Expect: all OK (repos without .dockerignore are skipped). Any BUG entries will break Docker builds.
## 4. Check stale package-lock.json files
@ -95,19 +71,11 @@ Expect: all OK. Any BUG entries will break Docker builds.
```bash
REPOS_DIR="/Users/sd9235/code/mygh"
echo "=== Stale package-lock.json ==="
for repo in \
learning_voice_ai_agent \
learning_ai_clock \
learning_ai_fastgap \
learning_ai_jarvis_jr \
learning_ai_peakpulse \
learning_ai_notes \
learning_ai_flowmonk \
learning_ai_trails \
learning_ai_local_memory_gpt; do
while IFS= read -r repo; do
[[ -z "$repo" || "$repo" =~ ^# ]] && continue
found=$(find "$REPOS_DIR/$repo" -name "package-lock.json" -not -path "*/node_modules/*" 2>/dev/null)
if [ -n "$found" ]; then echo "STALE: $found"; fi
done
done < /Users/sd9235/code/mygh/learning_ai_common_plat/.windsurf/workflows/repos.txt
echo "(empty = all clean)"
```
@ -120,17 +88,9 @@ Expect: no output. Remove any stale lockfiles found.
```bash
REPOS_DIR="/Users/sd9235/code/mygh"
echo "=== Dockerfile base image + NODE_TLS ==="
for repo in \
learning_voice_ai_agent \
learning_ai_clock \
learning_ai_fastgap \
learning_ai_jarvis_jr \
learning_ai_peakpulse \
learning_ai_notes \
learning_ai_flowmonk \
learning_ai_trails \
learning_ai_local_memory_gpt; do
for df in $(git -C "$REPOS_DIR/$repo" ls-files '*/Dockerfile' 2>/dev/null); do
while IFS= read -r repo; do
[[ -z "$repo" || "$repo" =~ ^# ]] && continue
for df in $(git -C "$REPOS_DIR/$repo" ls-files '*/Dockerfile' 'Dockerfile' 2>/dev/null); do
full="$REPOS_DIR/$repo/$df"
base=$(grep -m1 '^FROM' "$full" | awk '{print $2}')
tls=$(grep -c 'NODE_TLS_REJECT_UNAUTHORIZED' "$full" 2>/dev/null)
@ -139,7 +99,7 @@ for repo in \
[[ "$tls" == "0" && "$df" != *python* ]] && status="$status WARN:no-NODE_TLS"
echo "$repo/$df: base=$base tls=$tls $status"
done
done
done < /Users/sd9235/code/mygh/learning_ai_common_plat/.windsurf/workflows/repos.txt
```
Expect: all use `node:22-slim`, all have `NODE_TLS` refs > 0. Fix any WARN entries.
@ -151,15 +111,9 @@ Expect: all use `node:22-slim`, all have `NODE_TLS` refs > 0. Fix any WARN entri
```bash
REPOS_DIR="/Users/sd9235/code/mygh"
echo "=== next.config.ts: transpilePackages + symlinks ==="
for repo in \
learning_voice_ai_agent \
learning_ai_clock \
learning_ai_fastgap \
learning_ai_jarvis_jr \
learning_ai_notes \
learning_ai_trails \
learning_ai_local_memory_gpt; do
for cfg in $(find "$REPOS_DIR/$repo" -maxdepth 2 -name "next.config.ts" -not -path "*/node_modules/*" 2>/dev/null); do
while IFS= read -r repo; do
[[ -z "$repo" || "$repo" =~ ^# ]] && continue
for cfg in $(find "$REPOS_DIR/$repo" -maxdepth 3 -name "next.config.ts" -not -path "*/node_modules/*" 2>/dev/null); do
relpath="${cfg#$REPOS_DIR/}"
tp=$(grep -c 'transpilePackages' "$cfg")
sl=$(grep -c 'symlinks' "$cfg")
@ -168,7 +122,7 @@ for repo in \
[[ "$sl" == "0" ]] && status="$status MISSING:symlinks"
echo "$relpath: transpile=$tp symlinks=$sl $status"
done
done
done < /Users/sd9235/code/mygh/learning_ai_common_plat/.windsurf/workflows/repos.txt
```
Expect: all show transpile>0 and symlinks>0. Fix any MISSING entries.
@ -180,17 +134,10 @@ Expect: all show transpile>0 and symlinks>0. Fix any MISSING entries.
```bash
REPOS_DIR="/Users/sd9235/code/mygh"
echo "=== pnpm-workspace.yaml includes common-plat ==="
for repo in \
learning_voice_ai_agent \
learning_ai_clock \
learning_ai_fastgap \
learning_ai_jarvis_jr \
learning_ai_peakpulse \
learning_ai_notes \
learning_ai_flowmonk \
learning_ai_trails \
learning_ai_local_memory_gpt; do
while IFS= read -r repo; do
[[ -z "$repo" || "$repo" =~ ^# ]] && continue
ws="$REPOS_DIR/$repo/pnpm-workspace.yaml"
[[ ! -f "$ws" ]] && continue
if [ ! -f "$ws" ]; then
echo "$repo: MISSING pnpm-workspace.yaml"
elif grep -q 'common_plat' "$ws"; then
@ -198,10 +145,10 @@ for repo in \
else
echo "$repo: MISSING common-plat in workspace"
fi
done
done < /Users/sd9235/code/mygh/learning_ai_common_plat/.windsurf/workflows/repos.txt
```
Expect: all OK. Fix any MISSING entries.
Expect: all OK (repos without pnpm-workspace.yaml are skipped). Fix any MISSING entries.
## 8. Check docker-prep.sh uses shared prep-consumer
@ -210,16 +157,8 @@ Expect: all OK. Fix any MISSING entries.
```bash
REPOS_DIR="/Users/sd9235/code/mygh"
echo "=== docker-prep.sh uses shared prep-consumer ==="
for repo in \
learning_voice_ai_agent \
learning_ai_clock \
learning_ai_fastgap \
learning_ai_jarvis_jr \
learning_ai_peakpulse \
learning_ai_notes \
learning_ai_flowmonk \
learning_ai_trails \
learning_ai_local_memory_gpt; do
while IFS= read -r repo; do
[[ -z "$repo" || "$repo" =~ ^# ]] && continue
script="$REPOS_DIR/$repo/scripts/docker-prep.sh"
if [ ! -f "$script" ]; then
echo "$repo: NO docker-prep.sh"
@ -228,10 +167,10 @@ for repo in \
else
echo "$repo: WARN — legacy docker-prep.sh"
fi
done
done < /Users/sd9235/code/mygh/learning_ai_common_plat/.windsurf/workflows/repos.txt
```
Expect: all OK. Legacy scripts should be replaced with the shared wrapper.
Expect: all OK (repos without docker-prep.sh are skipped). Legacy scripts should be replaced with the shared wrapper.
## 9. Check verify scripts reference correct package filter names
@ -240,19 +179,12 @@ Expect: all OK. Legacy scripts should be replaced with the shared wrapper.
```bash
REPOS_DIR="/Users/sd9235/code/mygh"
echo "=== Root verify scripts ==="
for repo in \
learning_voice_ai_agent \
learning_ai_clock \
learning_ai_fastgap \
learning_ai_jarvis_jr \
learning_ai_peakpulse \
learning_ai_notes \
learning_ai_flowmonk \
learning_ai_trails \
learning_ai_local_memory_gpt; do
while IFS= read -r repo; do
[[ -z "$repo" || "$repo" =~ ^# ]] && continue
[[ ! -f "$REPOS_DIR/$repo/package.json" ]] && continue
printf "%-40s " "$repo:"
node -e "const p=require('$REPOS_DIR/$repo/package.json'); console.log(p.scripts?.verify || 'NONE')" 2>/dev/null
done
done < /Users/sd9235/code/mygh/learning_ai_common_plat/.windsurf/workflows/repos.txt
```
Review output manually — ensure `--filter` names match actual package names in sub-packages.

View File

@ -30,22 +30,14 @@ Each push triggers the `.gitea/workflows/ci.yml` workflow on the local runner.
```bash
REPOS_DIR="/Users/sd9235/code/mygh"
for repo in \
learning_ai_common_plat \
learning_voice_ai_agent \
learning_multimodal_memory_agents \
learning_ai_clock \
learning_ai_fastgap \
learning_ai_jarvis_jr \
learning_ai_peakpulse \
learning_ai_notes \
learning_ai_flowmonk \
learning_ai_trails \
learning_ai_local_memory_gpt; do
while IFS= read -r repo; do
[[ -z "$repo" || "$repo" =~ ^# ]] && continue
cd "$REPOS_DIR/$repo" 2>/dev/null || continue
# Skip repos without a gitea remote
git remote get-url gitea &>/dev/null || continue
echo "=== $repo ==="
cd "$REPOS_DIR/$repo"
git push gitea main 2>&1 | tail -2
done
done < /Users/sd9235/code/mygh/learning_ai_common_plat/.windsurf/workflows/repos.txt
```
## 4. Wait for jobs to process, then check results
@ -54,20 +46,14 @@ Wait ~2 minutes per repo for the runner (capacity=1) to process the queue, then
```bash
REPOS_DIR="/Users/sd9235/code/mygh"
for repo in \
learning_ai_common_plat \
learning_ai_clock \
learning_ai_trails \
learning_ai_flowmonk \
learning_ai_notes \
learning_ai_fastgap \
learning_ai_jarvis_jr \
learning_ai_peakpulse \
learning_ai_local_memory_gpt \
learning_voice_ai_agent \
learning_multimodal_memory_agents; do
while IFS= read -r repo; do
[[ -z "$repo" || "$repo" =~ ^# ]] && continue
cd "$REPOS_DIR/$repo" 2>/dev/null || continue
git remote get-url gitea &>/dev/null || continue
# Use basename for Gitea API (oss/learning_ai_claw-cowork → learning_ai_claw-cowork)
repo_name=$(basename "$repo")
echo "=== $repo ==="
curl -s -u "bytelyst:bytelyst123" "http://localhost:3300/api/v1/repos/bytelyst/$repo/actions/jobs" | python3 -c "
curl -s -u "bytelyst:bytelyst123" "http://localhost:3300/api/v1/repos/bytelyst/$repo_name/actions/jobs" | python3 -c "
import sys, json
jobs = json.load(sys.stdin).get('jobs', [])
if not jobs:
@ -80,7 +66,7 @@ else:
icon = '✅' if c == 'success' else '❌' if c == 'failure' else '⏳'
print(f' {icon} {c:12} {j[\"name\"]}')
" 2>/dev/null
done
done < /Users/sd9235/code/mygh/learning_ai_common_plat/.windsurf/workflows/repos.txt
```
## 5. (Optional) View logs for a failing job

View File

@ -0,0 +1,139 @@
---
description: Publish only outdated @bytelyst/* packages to the Gitea npm registry
---
# Publish Outdated Packages to Gitea Registry
Detects which `@bytelyst/*` packages in `packages/` have local changes compared to what's published in the Gitea npm registry, and republishes only the outdated ones.
**Registry (auto-detected via `NETWORK` env var):**
- `NETWORK=corp``http://localhost:3300` (SSH tunnel to Azure VM)
- `NETWORK=home``http://<azure-vm>:3300` (direct, from `~/.gitea_vm_host` or `gitea.bytelyst.com`)
**Auth:** `GITEA_NPM_TOKEN` env var (auto-loaded from `~/.gitea_npm_token` by `switch-network.sh`)
**Token scope required:** `read:package` + `write:package`
---
## Prerequisites
The Gitea NPM token must have **both** `read:package` and `write:package` scopes.
To create/update the token:
1. Open Gitea token settings:
- **Corp network:** `http://localhost:3300/-/user/settings/applications`
- **Home network:** `http://<azure-vm>:3300/-/user/settings/applications`
2. Create a new token with scopes: `read:package`, `write:package`
3. Save it: `echo "<token>" > ~/.gitea_npm_token`
4. Reload shell: `source ~/.zshrc`
---
## Steps
### 1. Verify prerequisites
// turbo
```bash
echo "Token: ${GITEA_NPM_TOKEN:0:5}..." && curl -s -o /dev/null -w "Gitea HTTP: %{http_code}\n" "http://${GITEA_NPM_HOST:-localhost}:3300/"
```
### 2. Dry-run: detect outdated packages
Run the script in `--dry-run` mode first to see which packages need publishing without making any changes.
// turbo
```bash
cd /Users/sd9235/code/mygh/learning_ai_common_plat && bash scripts/publish-outdated-gitea-packages.sh --dry-run
```
Review the output:
- **UP-TO-DATE** — local content matches registry (no action needed)
- **OUTDATED** — local content differs from registry (will bump patch version + publish)
- **NOT FOUND** — version not in registry (will publish as-is)
- **SKIP** — native SDKs or packages without dist/
### 3. Publish outdated packages
If the dry-run shows outdated packages, run the script without `--dry-run` to publish them.
```bash
cd /Users/sd9235/code/mygh/learning_ai_common_plat && bash scripts/publish-outdated-gitea-packages.sh
```
The script will:
1. Build all packages (`pnpm build`)
2. Compare each package's local content fingerprint against the registry's
3. For outdated packages: auto-bump the patch version (e.g., 0.1.0 -> 0.1.1) and publish
4. For not-found packages: publish as-is (current version)
5. Print which `package.json` files were bumped so you can commit them
### 4. Commit version bumps
After publishing, the script reports which `package.json` files had their version bumped. Commit them:
```bash
cd /Users/sd9235/code/mygh/learning_ai_common_plat && git add packages/*/package.json && git commit -m "chore(packages): bump versions for Gitea registry publish"
```
### 5. (Optional) Publish a single package
```bash
cd /Users/sd9235/code/mygh/learning_ai_common_plat && bash scripts/publish-outdated-gitea-packages.sh --filter @bytelyst/errors
```
### 6. (Optional) Skip the build step
If you already ran `pnpm build`:
```bash
cd /Users/sd9235/code/mygh/learning_ai_common_plat && bash scripts/publish-outdated-gitea-packages.sh --skip-build
```
---
## How detection works
For each package in `packages/`:
1. `pnpm pack` creates a local tarball
2. Downloads the same version's tarball from the registry
3. Extracts both and computes SHA-256 fingerprints of all file contents
4. If fingerprints differ (or version not in registry) -> marked for publish
This is metadata-independent (ignores tar timestamps) and catches any source/dist change.
## Corp proxy handling
When `NETWORK=corp`, the script automatically:
- Routes to `http://localhost:3300` (SSH tunnel) instead of the Azure VM
- Unsets all `NPM_CONFIG_*` and `*_proxy` env vars for the `npm publish` command
On both networks, the script:
- Strips `publishConfig.registry` from tarballs (avoids hardcoded external domain)
- Runs `npm publish` from `/tmp` (avoids repo `.npmrc` scoped registry override)
---
## Troubleshooting
| Issue | Fix |
| ----------------------------- | ----------------------------------------------------------------------------------------------------- |
| `GITEA_NPM_TOKEN is required` | Run `source ~/.zshrc` or `export GITEA_NPM_TOKEN=$(cat ~/.gitea_npm_token)` |
| Gitea unreachable | Check if Gitea VM is running. Verify `GITEA_NPM_HOST` resolves |
| E401 on publish | Token needs `write:package` scope. Regenerate at `http://localhost:3300/-/user/settings/applications` |
| All packages show OUTDATED | Normal after first run. Subsequent runs will show UP-TO-DATE for unchanged packages |
| Package has no dist/ | Run `pnpm build` first or don't use `--skip-build` |
## Script location
`scripts/publish-outdated-gitea-packages.sh` in `learning_ai_common_plat`
Run `bash scripts/publish-outdated-gitea-packages.sh --help` for usage.

View File

@ -0,0 +1,139 @@
---
description: Publish only outdated @bytelyst/* pnpm packages to the Gitea npm registry
---
# Publish Outdated pnpm Packages to Gitea Registry
Detects which `@bytelyst/*` pnpm packages in `packages/` have local changes compared to what's published in the Gitea npm registry, and republishes only the outdated ones.
**Registry (auto-detected via `NETWORK` env var):**
- `NETWORK=corp``http://localhost:3300` (SSH tunnel to Azure VM)
- `NETWORK=home``http://<azure-vm>:3300` (direct, from `~/.gitea_vm_host` or `gitea.bytelyst.com`)
**Auth:** `GITEA_NPM_TOKEN` env var (auto-loaded from `~/.gitea_npm_token` by `switch-network.sh`)
**Token scope required:** `read:package` + `write:package`
---
## Prerequisites
The Gitea NPM token must have **both** `read:package` and `write:package` scopes.
To create/update the token:
1. Open Gitea token settings:
- **Corp network:** `http://localhost:3300/-/user/settings/applications`
- **Home network:** `http://<azure-vm>:3300/-/user/settings/applications`
2. Create a new token with scopes: `read:package`, `write:package`
3. Save it: `echo "<token>" > ~/.gitea_npm_token`
4. Reload shell: `source ~/.zshrc`
---
## Steps
### 1. Verify prerequisites
// turbo
```bash
echo "Token: ${GITEA_NPM_TOKEN:0:5}..." && curl -s -o /dev/null -w "Gitea HTTP: %{http_code}\n" "http://${GITEA_NPM_HOST:-localhost}:3300/"
```
### 2. Dry-run: detect outdated packages
Run the script in `--dry-run` mode first to see which packages need publishing without making any changes.
// turbo
```bash
cd /Users/sd9235/code/mygh/learning_ai_common_plat && bash scripts/publish-outdated-gitea-packages.sh --dry-run
```
Review the output:
- **UP-TO-DATE** — local content matches registry (no action needed)
- **OUTDATED** — local content differs from registry (will bump patch version + publish)
- **NOT FOUND** — version not in registry (will publish as-is)
- **SKIP** — native SDKs or packages without dist/
### 3. Publish outdated packages
If the dry-run shows outdated packages, run the script without `--dry-run` to publish them.
```bash
cd /Users/sd9235/code/mygh/learning_ai_common_plat && bash scripts/publish-outdated-gitea-packages.sh
```
The script will:
1. Build all packages (`pnpm build`)
2. Compare each package's local content fingerprint against the registry's
3. For outdated packages: auto-bump the patch version (e.g., 0.1.0 -> 0.1.1) and publish
4. For not-found packages: publish as-is (current version)
5. Print which `package.json` files were bumped so you can commit them
### 4. Commit version bumps
After publishing, the script reports which `package.json` files had their version bumped. Commit them:
```bash
cd /Users/sd9235/code/mygh/learning_ai_common_plat && git add packages/*/package.json && git commit -m "chore(packages): bump versions for Gitea registry publish"
```
### 5. (Optional) Publish a single package
```bash
cd /Users/sd9235/code/mygh/learning_ai_common_plat && bash scripts/publish-outdated-gitea-packages.sh --filter @bytelyst/errors
```
### 6. (Optional) Skip the build step
If you already ran `pnpm build`:
```bash
cd /Users/sd9235/code/mygh/learning_ai_common_plat && bash scripts/publish-outdated-gitea-packages.sh --skip-build
```
---
## How detection works
For each package in `packages/`:
1. `pnpm pack` creates a local tarball
2. Downloads the same version's tarball from the registry
3. Extracts both and computes SHA-256 fingerprints of all file contents
4. If fingerprints differ (or version not in registry) -> marked for publish
This is metadata-independent (ignores tar timestamps) and catches any source/dist change.
## Corp proxy handling
When `NETWORK=corp`, the script automatically:
- Routes to `http://localhost:3300` (SSH tunnel) instead of the Azure VM
- Unsets all `NPM_CONFIG_*` and `*_proxy` env vars for the `npm publish` command
On both networks, the script:
- Strips `publishConfig.registry` from tarballs (avoids hardcoded external domain)
- Runs `npm publish` from `/tmp` (avoids repo `.npmrc` scoped registry override)
---
## Troubleshooting
| Issue | Fix |
| ----------------------------- | ----------------------------------------------------------------------------------------------------- |
| `GITEA_NPM_TOKEN is required` | Run `source ~/.zshrc` or `export GITEA_NPM_TOKEN=$(cat ~/.gitea_npm_token)` |
| Gitea unreachable | Check if Gitea VM is running. Verify `GITEA_NPM_HOST` resolves |
| E401 on publish | Token needs `write:package` scope. Regenerate at `http://localhost:3300/-/user/settings/applications` |
| All packages show OUTDATED | Normal after first run. Subsequent runs will show UP-TO-DATE for unchanged packages |
| Package has no dist/ | Run `pnpm build` first or don't use `--skip-build` |
## Script location
`scripts/publish-outdated-gitea-packages.sh` in `learning_ai_common_plat`
Run `bash scripts/publish-outdated-gitea-packages.sh --help` for usage.

View File

@ -30,3 +30,6 @@ learning_ai_productivity_web
# --- OSS (subdirectory repos under oss/) ---
oss/learning_ai_claw-code-oss
oss/learning_ai_claw-cowork
# -- tooling --
learning_ai_mac_tooling

View File

@ -39,7 +39,7 @@ for entry in \
"learning_ai_peakpulse:@peakpulse/backend" \
"learning_voice_ai_agent:@lysnrai/backend" \
"learning_ai_flowmonk:@flowmonk/backend" \
"learning_ai_notes:@notelett/backend"; do
"learning_ai_efforise:@efforise/backend"; do
repo="${entry%%:*}"
filter="${entry##*:}"
@ -83,7 +83,9 @@ for entry in \
"learning_ai_clock:web" \
"learning_ai_jarvis_jr:jarvisjr-web" \
"learning_voice_ai_agent:user-dashboard-web" \
"learning_ai_flowmonk:@flowmonk/web"; do
"learning_ai_flowmonk:@flowmonk/web" \
"learning_ai_efforise:client" \
"learning_ai_local_llms:dashboard"; do
repo="${entry%%:*}"
filter="${entry##*:}"

View File

@ -53,14 +53,43 @@ function countMatches(text: string, patterns: RegExp[]): number {
return count;
}
/**
* Check if messages contain image content parts (vision request).
* Handles both string content and multipart content arrays.
*/
function hasImageContent(messages: { role: string; content: string | unknown[] }[]): boolean {
for (const msg of messages) {
if (Array.isArray(msg.content)) {
for (const part of msg.content) {
if (
typeof part === 'object' &&
part !== null &&
'type' in part &&
(part as { type: string }).type === 'image_url'
) {
return true;
}
}
}
}
return false;
}
/**
* Classify a prompt into a category based on keyword matching.
* No LLM needed pure regex heuristics.
* Detects vision (image) content and returns 'vision' category when present.
*/
export function classifyPrompt(
messages: { role: string; content: string }[]
messages: { role: string; content: string | unknown[] }[]
): ClassificationResult {
const fullText = messages.map(m => m.content).join('\n');
// Check for vision content first — image inputs always classify as 'vision'
if (hasImageContent(messages)) {
const fullText = messages.map(m => (typeof m.content === 'string' ? m.content : '')).join('\n');
return { category: 'vision', estimatedTokens: estimateTokens(fullText) + 1000 };
}
const fullText = messages.map(m => (typeof m.content === 'string' ? m.content : '')).join('\n');
const estimatedTokens = estimateTokens(fullText);
const scores: Record<PromptCategory, number> = {
@ -69,6 +98,7 @@ export function classifyPrompt(
reasoning: countMatches(fullText, REASONING_PATTERNS),
creative: countMatches(fullText, CREATIVE_PATTERNS),
general: 1, // baseline
vision: 0,
};
// Pick highest scoring category

View File

@ -24,8 +24,9 @@ export const PAID_PROVIDERS: ProviderConfig[] = [
id: 'gpt-4o',
label: 'GPT-4o',
contextWindow: 128_000,
strengths: ['general', 'reasoning', 'code', 'creative'],
strengths: ['general', 'reasoning', 'code', 'creative', 'vision'],
speedTier: 2,
supportsVision: true,
},
],
},

View File

@ -18,6 +18,12 @@ export function createRoundRobinState(): Map<string, number> {
function scoreModel(model: ModelConfig, category: PromptCategory): number {
let score = 0;
// Vision requests require vision-capable models
if (category === 'vision') {
if (!model.supportsVision) return -1; // Exclude non-vision models
score += 15; // Strong boost for vision capability
}
// Direct strength match is the strongest signal
if (model.strengths.includes(category)) {
score += 10;
@ -56,6 +62,7 @@ export function selectCandidates(
if (!health.isHealthy(provider.name, model.id)) continue;
const score = scoreModel(model, category);
if (score < 0) continue; // Skip incompatible models (e.g. non-vision for vision requests)
candidates.push({ provider, model, score });
}
}

View File

@ -11,6 +11,10 @@ export interface ModelConfig {
strengths: PromptCategory[];
/** Relative speed tier: 1 = fastest, 3 = slowest */
speedTier: 1 | 2 | 3;
/** Whether the model supports vision (image) inputs */
supportsVision?: boolean;
/** Whether the model supports text embedding generation */
supportsEmbedding?: boolean;
}
export interface ProviderConfig {
@ -32,7 +36,7 @@ export interface ProviderConfig {
// ── Prompt Classification ──────────────────────────────────────
export type PromptCategory = 'code' | 'math' | 'reasoning' | 'creative' | 'general';
export type PromptCategory = 'code' | 'math' | 'reasoning' | 'creative' | 'general' | 'vision';
export interface ClassificationResult {
category: PromptCategory;

45
pnpm-lock.yaml generated
View File

@ -194,7 +194,7 @@ importers:
version: 9.39.2(jiti@2.6.1)
eslint-config-next:
specifier: 16.1.6
version: 16.1.6(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
version: 16.1.6(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
husky:
specifier: ^9.0.0
version: 9.1.7
@ -291,7 +291,7 @@ importers:
version: 9.39.2(jiti@2.6.1)
eslint-config-next:
specifier: 16.1.6
version: 16.1.6(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
version: 16.1.6(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
husky:
specifier: ^9.0.0
version: 9.1.7
@ -19570,23 +19570,23 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.0.3
'@vitest/mocker@3.2.4(msw@2.12.10(@types/node@20.19.33)(typescript@5.9.3))(vite@6.4.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))':
'@vitest/mocker@3.2.4(msw@2.12.10(@types/node@20.19.33)(typescript@5.9.3))(vite@7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
msw: 2.12.10(@types/node@20.19.33)(typescript@5.9.3)
vite: 6.4.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
vite: 7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
'@vitest/mocker@3.2.4(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))':
'@vitest/mocker@3.2.4(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
msw: 2.12.10(@types/node@22.19.11)(typescript@5.9.3)
vite: 6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
vite: 7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
'@vitest/mocker@4.0.18(msw@2.12.10(@types/node@20.19.33)(typescript@5.9.3))(vite@7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
@ -20897,7 +20897,7 @@ snapshots:
'@next/eslint-plugin-next': 16.1.6
eslint: 9.39.2(jiti@2.6.1)
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1))
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@2.6.1))
@ -20920,7 +20920,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)):
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)):
dependencies:
'@nolyfill/is-core-module': 1.0.39
debug: 4.4.3
@ -20935,6 +20935,21 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)):
dependencies:
'@nolyfill/is-core-module': 1.0.39
debug: 4.4.3
eslint: 9.39.2(jiti@2.6.1)
get-tsconfig: 4.13.6
is-bun-module: 2.0.0
stable-hash: 0.0.5
tinyglobby: 0.2.15
unrs-resolver: 1.11.1
optionalDependencies:
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
dependencies:
debug: 3.2.7
@ -20946,14 +20961,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
eslint: 9.39.2(jiti@2.6.1)
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1))
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))
transitivePeerDependencies:
- supports-color
@ -20997,7 +21012,7 @@ snapshots:
doctrine: 2.1.0
eslint: 9.39.2(jiti@2.6.1)
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@ -25587,7 +25602,7 @@ snapshots:
dependencies:
'@types/chai': 5.2.3
'@vitest/expect': 3.2.4
'@vitest/mocker': 3.2.4(msw@2.12.10(@types/node@20.19.33)(typescript@5.9.3))(vite@6.4.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))
'@vitest/mocker': 3.2.4(msw@2.12.10(@types/node@20.19.33)(typescript@5.9.3))(vite@7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4
@ -25605,7 +25620,7 @@ snapshots:
tinyglobby: 0.2.15
tinypool: 1.1.1
tinyrainbow: 2.0.0
vite: 6.4.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
vite: 7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
vite-node: 3.2.4(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
why-is-node-running: 2.3.0
optionalDependencies:
@ -25631,7 +25646,7 @@ snapshots:
dependencies:
'@types/chai': 5.2.3
'@vitest/expect': 3.2.4
'@vitest/mocker': 3.2.4(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))
'@vitest/mocker': 3.2.4(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4
@ -25649,7 +25664,7 @@ snapshots:
tinyglobby: 0.2.15
tinypool: 1.1.1
tinyrainbow: 2.0.0
vite: 6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
vite-node: 3.2.4(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
why-is-node-running: 2.3.0
optionalDependencies: