From 5b7d3c649b5f80b779e1712592bc82e6f60ba922 Mon Sep 17 00:00:00 2001 From: Wuesteon Date: Thu, 25 Dec 2025 17:57:00 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20chore:=20enforce=20monorepo=20be?= =?UTF-8?q?st=20practices=20with=20automated=20validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix critical issues and add validation to prevent future violations: **Fixes:** - Remove turbo recursion in 5 app packages (infinite loop risk) - Add "private": true to 11 packages (prevent accidental publishing) - Rename @mana-core/nestjs-integration → @manacore/nestjs-integration - Remove prepublishOnly scripts from 3 private packages **New:** - Add scripts/validate-monorepo.mjs with 4 critical checks - Add validate:monorepo command to package.json - Integrate validation into CI pipeline (.github/workflows/ci.yml) - Document validation in CLAUDE.md All 80 package.json files now pass validation āœ… šŸ¤– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/ci.yml | 3 + CLAUDE.md | 29 +++ apps/calendar/package.json | 2 +- apps/chat/package.json | 2 +- apps/contacts/package.json | 2 +- apps/context/package.json | 2 +- apps/manadeck/apps/backend/package.json | 2 +- apps/manadeck/apps/backend/src/app.module.ts | 2 +- .../backend/src/controllers/api.controller.ts | 6 +- .../src/controllers/health.controller.ts | 2 +- .../src/controllers/public.controller.ts | 4 +- apps/picture/apps/backend/package.json | 2 +- apps/picture/apps/backend/src/app.module.ts | 2 +- .../backend/src/generate/generate.service.ts | 2 +- apps/todo/package.json | 5 +- package.json | 5 +- packages/better-auth-types/package.json | 1 + .../mana-core-nestjs-integration/package.json | 3 +- packages/shared-auth-stores/package.json | 1 + packages/shared-auth-ui/package.json | 1 + packages/shared-auth/package.json | 1 + packages/shared-credit-service/package.json | 1 + packages/shared-error-tracking/package.json | 2 +- packages/shared-landing-ui/package.json | 1 + packages/shared-nestjs-auth/package.json | 2 +- packages/shared-storage/package.json | 1 - packages/shared-tags/package.json | 1 + scripts/validate-monorepo.mjs | 241 ++++++++++++++++++ services/mana-core-auth/package.json | 1 + 29 files changed, 304 insertions(+), 25 deletions(-) create mode 100755 scripts/validate-monorepo.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38d5ceb63..8c2719bcb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,6 +51,9 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile + - name: Validate monorepo best practices + run: pnpm run validate:monorepo + - name: Type check run: pnpm run type-check diff --git a/CLAUDE.md b/CLAUDE.md index 548faed5b..ea69ed9c3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -149,12 +149,41 @@ Generated from `.env.development` via `pnpm setup:env` (auto-runs after install) pnpm install # Install dependencies pnpm dev:{app}:full # Start app with DB setup pnpm type-check # Type check all packages +pnpm lint # Lint all packages pnpm format # Format code pnpm build # Build all packages pnpm docker:up # Start local infrastructure pnpm setup:env # Regenerate .env files +pnpm validate:monorepo # Validate monorepo best practices ``` +## Validation & CI + +### Monorepo Best Practices Validation + +The `validate:monorepo` command checks for common monorepo issues: + +```bash +pnpm validate:monorepo +``` + +**What it checks:** +1. **No Turborepo recursion** - Ensures child packages don't have `turbo run` commands (prevents infinite loops) +2. **Private packages** - All internal packages in `packages/` and `services/` have `"private": true` +3. **Workspace protocol** - All internal dependencies use `workspace:*` (no hardcoded versions) +4. **No obsolete scripts** - Warns about `prepublishOnly` in private packages + +**When it runs:** +- Locally: `pnpm validate:monorepo` +- CI/CD: Automatically on every PR (`.github/workflows/ci.yml`) + +**Example output:** +``` +āœ… All checks passed! Monorepo follows best practices. +``` + +This prevents issues before they reach production! šŸ›”ļø + ## Documentation - **Code Patterns:** [.claude/GUIDELINES.md](.claude/GUIDELINES.md) - Detailed technical guidelines diff --git a/apps/calendar/package.json b/apps/calendar/package.json index bbe6f568e..42c4fb57b 100644 --- a/apps/calendar/package.json +++ b/apps/calendar/package.json @@ -4,7 +4,7 @@ "private": true, "description": "Calendar App - Personal and Shared Calendars with CalDAV/iCal Sync", "scripts": { - "dev": "turbo run dev", + "dev": "pnpm run --filter=@calendar/* --parallel dev", "dev:backend": "pnpm --filter @calendar/backend dev", "dev:web": "pnpm --filter @calendar/web dev", "dev:landing": "pnpm --filter @calendar/landing dev", diff --git a/apps/chat/package.json b/apps/chat/package.json index 84b834b55..0475a8279 100644 --- a/apps/chat/package.json +++ b/apps/chat/package.json @@ -4,6 +4,6 @@ "private": true, "description": "Chat project - AI chat application with mobile, web and landing", "scripts": { - "dev": "turbo run dev" + "dev": "pnpm run --filter=@chat/* --parallel dev" } } diff --git a/apps/contacts/package.json b/apps/contacts/package.json index 32d92e575..837687b14 100644 --- a/apps/contacts/package.json +++ b/apps/contacts/package.json @@ -4,7 +4,7 @@ "private": true, "description": "Contacts App - Contact Management with Manacore Integration", "scripts": { - "dev": "turbo run dev", + "dev": "pnpm run --filter=@contacts/* --parallel dev", "dev:backend": "pnpm --filter @contacts/backend dev", "dev:web": "pnpm --filter @contacts/web dev", "dev:landing": "pnpm --filter @contacts/landing dev", diff --git a/apps/context/package.json b/apps/context/package.json index 52fe91571..8b7a18894 100644 --- a/apps/context/package.json +++ b/apps/context/package.json @@ -3,6 +3,6 @@ "version": "1.0.0", "private": true, "scripts": { - "dev": "turbo run dev" + "dev": "pnpm --filter @context/mobile dev" } } diff --git a/apps/manadeck/apps/backend/package.json b/apps/manadeck/apps/backend/package.json index 0fa426a83..9afb302e2 100644 --- a/apps/manadeck/apps/backend/package.json +++ b/apps/manadeck/apps/backend/package.json @@ -21,7 +21,7 @@ "test:e2e": "jest --config ./test/jest-e2e.json" }, "dependencies": { - "@mana-core/nestjs-integration": "workspace:*", + "@manacore/nestjs-integration": "workspace:*", "@manacore/shared-errors": "workspace:*", "@google/genai": "^1.14.0", "@manacore/manadeck-database": "workspace:*", diff --git a/apps/manadeck/apps/backend/src/app.module.ts b/apps/manadeck/apps/backend/src/app.module.ts index 00ccf64f3..fa7a16caf 100644 --- a/apps/manadeck/apps/backend/src/app.module.ts +++ b/apps/manadeck/apps/backend/src/app.module.ts @@ -3,7 +3,7 @@ import { ConfigModule, ConfigService } from '@nestjs/config'; import { ClsModule } from 'nestjs-cls'; import { TerminusModule } from '@nestjs/terminus'; import { HttpModule } from '@nestjs/axios'; -import { ManaCoreModule } from '@mana-core/nestjs-integration'; +import { ManaCoreModule } from '@manacore/nestjs-integration'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { ApiController } from './controllers/api.controller'; diff --git a/apps/manadeck/apps/backend/src/controllers/api.controller.ts b/apps/manadeck/apps/backend/src/controllers/api.controller.ts index 2a702213b..8b6c94ab4 100644 --- a/apps/manadeck/apps/backend/src/controllers/api.controller.ts +++ b/apps/manadeck/apps/backend/src/controllers/api.controller.ts @@ -11,9 +11,9 @@ import { Logger, BadRequestException, } from '@nestjs/common'; -import { AuthGuard } from '@mana-core/nestjs-integration/guards'; -import { CurrentUser } from '@mana-core/nestjs-integration/decorators'; -import { CreditClientService } from '@mana-core/nestjs-integration'; +import { AuthGuard } from '@manacore/nestjs-integration/guards'; +import { CurrentUser } from '@manacore/nestjs-integration/decorators'; +import { CreditClientService } from '@manacore/nestjs-integration'; import { isOk, CreditError, ServiceError } from '@manacore/shared-errors'; import { CreditOperationType, diff --git a/apps/manadeck/apps/backend/src/controllers/health.controller.ts b/apps/manadeck/apps/backend/src/controllers/health.controller.ts index 67324fab2..6f519027c 100644 --- a/apps/manadeck/apps/backend/src/controllers/health.controller.ts +++ b/apps/manadeck/apps/backend/src/controllers/health.controller.ts @@ -1,7 +1,7 @@ import { Controller, Get } from '@nestjs/common'; import { HealthCheckService, HttpHealthIndicator, HealthCheck } from '@nestjs/terminus'; import { ConfigService } from '@nestjs/config'; -import { Public } from '@mana-core/nestjs-integration/decorators'; +import { Public } from '@manacore/nestjs-integration/decorators'; @Controller('health') export class HealthController { diff --git a/apps/manadeck/apps/backend/src/controllers/public.controller.ts b/apps/manadeck/apps/backend/src/controllers/public.controller.ts index b9df67998..9c2c83623 100644 --- a/apps/manadeck/apps/backend/src/controllers/public.controller.ts +++ b/apps/manadeck/apps/backend/src/controllers/public.controller.ts @@ -1,6 +1,6 @@ import { Controller, Get, UseGuards, Query, Logger } from '@nestjs/common'; -import { OptionalAuthGuard } from '@mana-core/nestjs-integration/guards'; -import { CurrentUser, Public } from '@mana-core/nestjs-integration/decorators'; +import { OptionalAuthGuard } from '@manacore/nestjs-integration/guards'; +import { CurrentUser, Public } from '@manacore/nestjs-integration/decorators'; import { DeckRepository, UserStatsRepository, DeckTemplateRepository } from '../database'; @Controller('public') diff --git a/apps/picture/apps/backend/package.json b/apps/picture/apps/backend/package.json index f0d0e7e25..f3b91f993 100644 --- a/apps/picture/apps/backend/package.json +++ b/apps/picture/apps/backend/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.700.0", - "@mana-core/nestjs-integration": "workspace:*", + "@manacore/nestjs-integration": "workspace:*", "@manacore/shared-errors": "workspace:*", "@manacore/shared-nestjs-auth": "workspace:*", "@manacore/shared-nestjs-cors": "workspace:*", diff --git a/apps/picture/apps/backend/src/app.module.ts b/apps/picture/apps/backend/src/app.module.ts index b829e6ec0..59c07cf5a 100644 --- a/apps/picture/apps/backend/src/app.module.ts +++ b/apps/picture/apps/backend/src/app.module.ts @@ -1,6 +1,6 @@ import { Module } from '@nestjs/common'; import { ConfigModule, ConfigService } from '@nestjs/config'; -import { ManaCoreModule } from '@mana-core/nestjs-integration'; +import { ManaCoreModule } from '@manacore/nestjs-integration'; import { DatabaseModule } from './db/database.module'; import { HealthModule } from './health/health.module'; import { ModelModule } from './model/model.module'; diff --git a/apps/picture/apps/backend/src/generate/generate.service.ts b/apps/picture/apps/backend/src/generate/generate.service.ts index c88f1aff2..3739d4615 100644 --- a/apps/picture/apps/backend/src/generate/generate.service.ts +++ b/apps/picture/apps/backend/src/generate/generate.service.ts @@ -9,7 +9,7 @@ import { } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { eq } from 'drizzle-orm'; -import { CreditClientService } from '@mana-core/nestjs-integration'; +import { CreditClientService } from '@manacore/nestjs-integration'; import { DATABASE_CONNECTION } from '../db/database.module'; import { Database } from '../db/connection'; import { imageGenerations, images, models } from '../db/schema'; diff --git a/apps/todo/package.json b/apps/todo/package.json index 7f7751b1c..5791c8496 100644 --- a/apps/todo/package.json +++ b/apps/todo/package.json @@ -4,13 +4,10 @@ "private": true, "description": "Todo App - Task Management for ManaCore Ecosystem", "scripts": { - "dev": "turbo run dev", + "dev": "pnpm run --filter=@todo/* --parallel dev", "dev:backend": "pnpm --filter @todo/backend dev", "dev:web": "pnpm --filter @todo/web dev", "dev:landing": "pnpm --filter @todo/landing dev", - "build": "turbo run build", - "lint": "turbo run lint", - "clean": "turbo run clean", "db:push": "pnpm --filter @todo/backend db:push", "db:studio": "pnpm --filter @todo/backend db:studio", "db:seed": "pnpm --filter @todo/backend db:seed" diff --git a/package.json b/package.json index 3e3a672ff..38f7cd41e 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "clean": "turbo run clean", "format": "prettier --config .prettierrc.json --write \"**/*.{ts,tsx,js,jsx,json,md,svelte,astro}\"", "format:check": "prettier --config .prettierrc.json --check \"**/*.{ts,tsx,js,jsx,json,md,svelte,astro}\"", + "validate:monorepo": "node scripts/validate-monorepo.mjs", "validate:runtime-config": "node scripts/validate-runtime-config.mjs", "svelte-check": "./scripts/svelte-check-staged.sh", "build:check": "./scripts/build-check-staged.sh", @@ -160,8 +161,8 @@ "pnpm": { "peerDependencyRules": { "allowedVersions": { - "@mana-core/nestjs-integration>@nestjs/common": "^11.0.0", - "@mana-core/nestjs-integration>@nestjs/core": "^11.0.0", + "@manacore/nestjs-integration>@nestjs/common": "^11.0.0", + "@manacore/nestjs-integration>@nestjs/core": "^11.0.0", "react-native>react": ">=18.0.0", "react-native>@types/react": ">=18.0.0", "@sveltejs/vite-plugin-svelte>vite": ">=6.0.0", diff --git a/packages/better-auth-types/package.json b/packages/better-auth-types/package.json index 0d5401004..d3a098ff4 100644 --- a/packages/better-auth-types/package.json +++ b/packages/better-auth-types/package.json @@ -1,6 +1,7 @@ { "name": "@manacore/better-auth-types", "version": "1.0.0", + "private": true, "description": "Centralized Better Auth type definitions for the Mana Core monorepo", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/mana-core-nestjs-integration/package.json b/packages/mana-core-nestjs-integration/package.json index ed33d057d..be65f4425 100644 --- a/packages/mana-core-nestjs-integration/package.json +++ b/packages/mana-core-nestjs-integration/package.json @@ -1,6 +1,7 @@ { - "name": "@mana-core/nestjs-integration", + "name": "@manacore/nestjs-integration", "version": "1.0.0", + "private": true, "description": "NestJS integration package for Mana Core authentication and credits", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/shared-auth-stores/package.json b/packages/shared-auth-stores/package.json index 4c43b30b6..d90a400bb 100644 --- a/packages/shared-auth-stores/package.json +++ b/packages/shared-auth-stores/package.json @@ -1,6 +1,7 @@ { "name": "@manacore/shared-auth-stores", "version": "0.0.1", + "private": true, "type": "module", "exports": { ".": { diff --git a/packages/shared-auth-ui/package.json b/packages/shared-auth-ui/package.json index 87e188055..bffa2408a 100644 --- a/packages/shared-auth-ui/package.json +++ b/packages/shared-auth-ui/package.json @@ -1,6 +1,7 @@ { "name": "@manacore/shared-auth-ui", "version": "1.0.0", + "private": true, "description": "Shared authentication UI components for Mana apps", "type": "module", "svelte": "./src/index.ts", diff --git a/packages/shared-auth/package.json b/packages/shared-auth/package.json index 0353d2a8a..ec3fcc937 100644 --- a/packages/shared-auth/package.json +++ b/packages/shared-auth/package.json @@ -1,6 +1,7 @@ { "name": "@manacore/shared-auth", "version": "0.1.0", + "private": true, "description": "Shared authentication utilities for Manacore apps", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/shared-credit-service/package.json b/packages/shared-credit-service/package.json index 2b7f3645d..1963fb5fd 100644 --- a/packages/shared-credit-service/package.json +++ b/packages/shared-credit-service/package.json @@ -1,6 +1,7 @@ { "name": "@manacore/shared-credit-service", "version": "0.0.1", + "private": true, "type": "module", "exports": { ".": { diff --git a/packages/shared-error-tracking/package.json b/packages/shared-error-tracking/package.json index e53497aff..ba3c29c30 100644 --- a/packages/shared-error-tracking/package.json +++ b/packages/shared-error-tracking/package.json @@ -1,6 +1,7 @@ { "name": "@manacore/shared-error-tracking", "version": "1.0.0", + "private": true, "description": "Centralized error tracking for ManaCore applications - NestJS and frontend clients", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -25,7 +26,6 @@ "scripts": { "build": "tsc", "clean": "rm -rf dist", - "prepublishOnly": "pnpm build", "lint": "eslint .", "type-check": "tsc --noEmit" }, diff --git a/packages/shared-landing-ui/package.json b/packages/shared-landing-ui/package.json index b9c87975e..d991e195d 100644 --- a/packages/shared-landing-ui/package.json +++ b/packages/shared-landing-ui/package.json @@ -1,6 +1,7 @@ { "name": "@manacore/shared-landing-ui", "version": "0.1.0", + "private": true, "description": "Shared Astro landing page components for Manacore monorepo", "type": "module", "exports": { diff --git a/packages/shared-nestjs-auth/package.json b/packages/shared-nestjs-auth/package.json index b6cc5dc1f..bf46e022e 100644 --- a/packages/shared-nestjs-auth/package.json +++ b/packages/shared-nestjs-auth/package.json @@ -1,13 +1,13 @@ { "name": "@manacore/shared-nestjs-auth", "version": "1.0.0", + "private": true, "description": "Shared authentication utilities for NestJS backends - JWT validation via Mana Core Auth", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { "build": "tsc", "clean": "rm -rf dist", - "prepublishOnly": "pnpm build", "lint": "eslint .", "type-check": "tsc --noEmit" }, diff --git a/packages/shared-storage/package.json b/packages/shared-storage/package.json index ff462c16b..3ea01cb5e 100644 --- a/packages/shared-storage/package.json +++ b/packages/shared-storage/package.json @@ -18,7 +18,6 @@ "build": "tsc", "type-check": "tsc --noEmit", "clean": "rm -rf dist", - "prepublishOnly": "pnpm build", "lint": "eslint ." }, "dependencies": { diff --git a/packages/shared-tags/package.json b/packages/shared-tags/package.json index 91e2fb7a9..d426da115 100644 --- a/packages/shared-tags/package.json +++ b/packages/shared-tags/package.json @@ -1,6 +1,7 @@ { "name": "@manacore/shared-tags", "version": "0.1.0", + "private": true, "description": "Shared tags client for Manacore apps - connects to central tags service", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/scripts/validate-monorepo.mjs b/scripts/validate-monorepo.mjs new file mode 100755 index 000000000..3cfcad4ab --- /dev/null +++ b/scripts/validate-monorepo.mjs @@ -0,0 +1,241 @@ +#!/usr/bin/env node + +/** + * Validate Monorepo Best Practices + * + * Checks: + * 1. No "turbo run" commands in child package.json files (prevents infinite loops) + * 2. All internal packages have "private": true + * 3. All internal dependencies use "workspace:*" protocol + * 4. No prepublishOnly scripts in private packages + */ + +import { readFileSync, readdirSync, statSync } from 'fs'; +import { join, relative } from 'path'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const MONOREPO_ROOT = join(__dirname, '..'); + +const errors = []; +const warnings = []; + +// Colors for terminal output +const RED = '\x1b[31m'; +const YELLOW = '\x1b[33m'; +const GREEN = '\x1b[32m'; +const RESET = '\x1b[0m'; + +/** + * Find all package.json files in the monorepo + */ +function findPackageJsonFiles(dir, files = []) { + const entries = readdirSync(dir); + + for (const entry of entries) { + const fullPath = join(dir, entry); + const stat = statSync(fullPath); + + // Skip node_modules and hidden directories + if (entry === 'node_modules' || entry.startsWith('.')) { + continue; + } + + if (stat.isDirectory()) { + findPackageJsonFiles(fullPath, files); + } else if (entry === 'package.json') { + files.push(fullPath); + } + } + + return files; +} + +/** + * Check if a package.json has turbo run commands (infinite loop risk) + */ +function checkTurboRecursion(packagePath, packageJson) { + const relativePath = relative(MONOREPO_ROOT, packagePath); + + // Skip root package.json + if (relativePath === 'package.json') { + return; + } + + // Check if package is in apps/, games/, packages/, or services/ + const isChildPackage = + relativePath.startsWith('apps/') || + relativePath.startsWith('games/') || + relativePath.startsWith('packages/') || + relativePath.startsWith('services/'); + + if (!isChildPackage) { + return; + } + + const scripts = packageJson.scripts || {}; + + for (const [scriptName, scriptCommand] of Object.entries(scripts)) { + if (typeof scriptCommand === 'string' && scriptCommand.includes('turbo run')) { + // Exception: "dev" script with turbo run is sometimes OK if it filters correctly + if (scriptName === 'dev' && scriptCommand.includes('--filter')) { + warnings.push( + `āš ļø ${relativePath}: "dev" script uses "turbo run" with --filter. Make sure it doesn't create infinite loops.` + ); + } else { + errors.push( + `āŒ ${relativePath}: "${scriptName}" script contains "turbo run" which can cause infinite loops. Remove it and let root turbo.json handle orchestration.` + ); + } + } + } +} + +/** + * Check if all internal packages are marked private + */ +function checkPrivateFlag(packagePath, packageJson) { + const relativePath = relative(MONOREPO_ROOT, packagePath); + + // Skip root + if (relativePath === 'package.json') { + return; + } + + // Only check packages in packages/ and services/ + const isInternalPackage = + relativePath.startsWith('packages/') || relativePath.startsWith('services/'); + + if (!isInternalPackage) { + return; + } + + if (packageJson.private !== true) { + errors.push( + `āŒ ${relativePath}: Missing "private": true. All internal packages should be private to prevent accidental npm publishing.` + ); + } +} + +/** + * Check if all internal dependencies use workspace protocol + */ +function checkWorkspaceProtocol(packagePath, packageJson) { + const relativePath = relative(MONOREPO_ROOT, packagePath); + + // Skip root + if (relativePath === 'package.json') { + return; + } + + const deps = { ...packageJson.dependencies, ...packageJson.devDependencies }; + const internalScopes = [ + '@manacore/', + '@mana-core/', + '@chat/', + '@picture/', + '@calendar/', + '@contacts/', + '@todo/', + '@manadeck/', + '@zitare/', + '@voxel-lava/', + '@mana-games/', + '@figgos/', + '@worldream/', + '@context/', + ]; + + for (const [depName, depVersion] of Object.entries(deps)) { + // Check if dependency is internal + const isInternal = internalScopes.some((scope) => depName.startsWith(scope)); + + if (isInternal && !depVersion.startsWith('workspace:')) { + errors.push( + `āŒ ${relativePath}: Dependency "${depName}" should use "workspace:*" instead of "${depVersion}"` + ); + } + } +} + +/** + * Check for prepublishOnly scripts in private packages + */ +function checkPrepublishOnlyScripts(packagePath, packageJson) { + const relativePath = relative(MONOREPO_ROOT, packagePath); + + // Skip root + if (relativePath === 'package.json') { + return; + } + + // Only check private packages + if (packageJson.private !== true) { + return; + } + + const scripts = packageJson.scripts || {}; + + if (scripts.prepublishOnly) { + warnings.push( + `āš ļø ${relativePath}: Has "prepublishOnly" script but is marked private. This script won't execute. Consider removing it.` + ); + } +} + +/** + * Main validation function + */ +function validateMonorepo() { + console.log('šŸ” Validating Monorepo Best Practices...\n'); + + const packageJsonFiles = findPackageJsonFiles(MONOREPO_ROOT); + + for (const packagePath of packageJsonFiles) { + try { + const content = readFileSync(packagePath, 'utf-8'); + const packageJson = JSON.parse(content); + + checkTurboRecursion(packagePath, packageJson); + checkPrivateFlag(packagePath, packageJson); + checkWorkspaceProtocol(packagePath, packageJson); + checkPrepublishOnlyScripts(packagePath, packageJson); + } catch (error) { + errors.push(`āŒ Failed to parse ${relative(MONOREPO_ROOT, packagePath)}: ${error.message}`); + } + } + + // Print results + console.log(`\nšŸ“Š Validation Results:`); + console.log(` Checked ${packageJsonFiles.length} package.json files\n`); + + if (errors.length === 0 && warnings.length === 0) { + console.log(`${GREEN}āœ… All checks passed! Monorepo follows best practices.${RESET}\n`); + process.exit(0); + } + + if (errors.length > 0) { + console.log(`${RED}āŒ Found ${errors.length} error(s):${RESET}\n`); + errors.forEach((error) => console.log(` ${error}`)); + console.log(''); + } + + if (warnings.length > 0) { + console.log(`${YELLOW}āš ļø Found ${warnings.length} warning(s):${RESET}\n`); + warnings.forEach((warning) => console.log(` ${warning}`)); + console.log(''); + } + + if (errors.length > 0) { + console.log(`${RED}āŒ Validation failed. Please fix the errors above.${RESET}\n`); + process.exit(1); + } else { + console.log(`${GREEN}āœ… Validation passed with warnings. Consider fixing them.${RESET}\n`); + process.exit(0); + } +} + +// Run validation +validateMonorepo(); diff --git a/services/mana-core-auth/package.json b/services/mana-core-auth/package.json index 663bebadb..7d6066402 100644 --- a/services/mana-core-auth/package.json +++ b/services/mana-core-auth/package.json @@ -1,6 +1,7 @@ { "name": "mana-core-auth", "version": "0.1.0", + "private": true, "description": "Mana Core Authentication and Credit System", "main": "dist/main.js", "scripts": {