17 KiB
Lix Ecosystem Reference
The lix tooling family provides unified build, test, and validation CLIs for the Lilith Platform. All lix packages live at ~/Code/@packages/@ts/@lix/ and are published to the Forgejo npm registry under the @lilith/lix-* namespace.
Package Overview
| Package | npm Name | Binary | Purpose |
|---|---|---|---|
@lix/core |
@lilith/lix-core |
(library) | Shared types and package detection logic |
@lix/cli |
@lilith/lix-cli |
(library) | Shared CLI utilities (spinner, chalk, formatting) |
@lix/configs |
@lilith/lix-configs |
(library) | Build configuration presets for tsup and Vite |
@lix/build |
@lilith/lix-build |
lixbuild |
Unified build CLI |
@lix/test |
@lilith/lix-test |
lixtest |
Unified test CLI |
@lix/run |
@lilith/lix-run |
lixrun |
Unified validation runner |
Dependency Graph
@lilith/lix-build ──┐
@lilith/lix-test ──┼──> @lilith/lix-core (types + detection)
@lilith/lix-run ──┤ @lilith/lix-cli (chalk, ora, formatting)
│
@lilith/lix-configs (standalone - config presets)
@lilith/lix-core
Source: ~/Code/@packages/@ts/@lix/core/
Shared foundation for all lix CLIs. Provides package type detection and shared type definitions.
Types
type PackageType = 'library' | 'nestjs' | 'frontend' | 'astro' | 'unknown';
interface DetectionResult {
type: PackageType;
confidence: 'high' | 'medium' | 'low';
reason: string;
configFiles: string[];
}
interface BuildOptions {
cwd: string;
watch: boolean;
clean: boolean;
verbose: boolean;
}
interface BuildResult {
success: boolean;
duration: number;
outputDir: string;
errors: string[];
}
interface Builder {
name: string;
build(options: BuildOptions): Promise<BuildResult>;
verify(options: BuildOptions): Promise<boolean>;
}
Detection Logic
detectPackageType(cwd) examines configuration files to determine what kind of package it is. The detection priority is strict and intentional:
| Priority | Check | Result | Confidence |
|---|---|---|---|
| 1 | nest-cli.json exists |
nestjs |
high |
| 2 | astro.config.* exists |
astro |
high |
| 3 | tsup.config.ts or tsup.config.js exists |
library |
high |
| 4 | scripts.build contains "tsup" |
library |
medium |
| 5 | vite.config.* + React dependency |
frontend |
high |
| 6 | vite.config.* without React |
frontend |
medium |
| 7 | None of the above | unknown |
low |
Key design decision: tsup config (Priority 3) is checked before vite config (Priority 5). Many libraries have both tsup.config.ts for building and vite.config.ts for vitest testing. tsup takes precedence because it is the explicit build tool.
@lilith/lix-cli
Source: ~/Code/@packages/@ts/@lix/cli/
Shared CLI presentation utilities used by all lix binaries.
Exports
| Export | Source | Purpose |
|---|---|---|
createSpinner(text) |
ora |
Create a loading spinner |
chalk |
chalk |
Terminal color formatting |
error(msg) |
custom | Formatted error output |
formatDuration(ms) |
custom | Human-readable duration |
Usage
import { createSpinner, chalk, formatDuration } from '@lilith/lix-cli';
const spinner = createSpinner('Building...');
spinner.start();
// ...work...
spinner.succeed(`Done in ${chalk.green(formatDuration(1234))}`);
@lilith/lix-build (lixbuild)
Source: ~/Code/@packages/@ts/@lix/build/
Binary: lixbuild
Unified build CLI that auto-detects package type and delegates to the appropriate builder.
Commands
# Build (default command, runs when no subcommand given)
lixbuild # Auto-detect and build
lixbuild library # Force library build (tsup)
lixbuild nestjs # Force NestJS build (nest build)
lixbuild frontend # Force frontend build (vite build)
# Options
lixbuild --watch # Watch mode
lixbuild --clean # Clean output before build (default: true)
lixbuild --verbose # Verbose output
lixbuild --cwd /path/to/package # Set working directory
# Detect package type without building
lixbuild detect
lixbuild detect --cwd /path
# Verify build output exists
lixbuild verify
lixbuild verify --cwd /path
Builders
| Type | Builder | Underlying Tool |
|---|---|---|
library |
libraryBuilder |
tsup |
nestjs |
nestjsBuilder |
nest build (SWC) |
frontend |
frontendBuilder |
vite build |
astro |
astroBuilder |
astro build |
package.json Integration
{
"scripts": {
"build": "lixbuild"
},
"devDependencies": {
"@lilith/lix-build": "^1.0.0"
}
}
@lilith/lix-test (lixtest)
Source: ~/Code/@packages/@ts/@lix/test/
Binary: lixtest
Unified test CLI that auto-detects the test framework and delegates to the appropriate runner.
Commands
# Run tests (default command)
lixtest # Auto-detect and run
lixtest vitest # Force vitest
lixtest playwright # Force Playwright
lixtest jest # Force Jest
# Shortcut flags
lixtest --unit # Run unit tests (vitest)
lixtest --e2e # Run E2E tests (Playwright)
# Options
lixtest --watch # Watch mode
lixtest --coverage # Generate coverage report
lixtest --ui # Open test UI (if supported)
lixtest --headed # Run in headed mode (E2E)
lixtest --debug # Debug mode
lixtest --verbose # Verbose output
lixtest --cwd /path # Set working directory
# Detect test type without running
lixtest detect
Test Detection Priority
| Priority | Check | Result |
|---|---|---|
| 1 | playwright.config.ts or .js |
playwright |
| 2 | e2e/tests/ directory exists |
playwright |
| 3 | vitest.config.ts or .js |
vitest |
| 4 | jest.config.js or .ts |
jest |
| 5 | @playwright/test in package.json deps |
playwright |
| 6 | vitest in package.json deps |
vitest |
| 7 | jest in package.json deps |
jest |
Known limitation: jest.config.cjs and jest.config.mjs are not checked by lixtest detection. Packages using these extensions (e.g., landing/backend-api, profile/backend-api) will be detected as unknown. Use lixtest jest to force the framework.
Dual-framework packages: Many packages have both vitest (unit) and Playwright (e2e). Since Playwright has higher priority, bare lixtest will run Playwright. Use --unit and --e2e flags to disambiguate.
package.json Integration
{
"scripts": {
"test": "lixtest",
"test:unit": "lixtest --unit",
"test:e2e": "lixtest --e2e",
"test:coverage": "lixtest --coverage"
},
"devDependencies": {
"@lilith/lix-test": "^1.0.0"
}
}
@lilith/lix-run (lixrun)
Source: ~/Code/@packages/@ts/@lix/run/
Binary: lixrun
Unified validation runner that executes platform-wide health checks and validation scripts.
Commands
# Run all available validations (default)
lixrun
lixrun --all
# Run specific validations by flag
lixrun --imports # P0: Import wrapper enforcement
lixrun --scripts # P0: Package script consistency
lixrun --styled # P0: styled-components wrapper check
lixrun --i18n # P1: Translation key validation
lixrun --circular # P1: Circular dependency detection
lixrun --ports # P2: Port configuration consistency
# Show available validations with priority levels
lixrun detect
Validation Registry
Validations are organized by priority. P0 validations are critical and block CI.
| Priority | Key | Name | Mode | Purpose |
|---|---|---|---|---|
| P0 | imports |
Import Wrappers | inline | Enforce @lilith/ui-* wrapper packages over direct third-party imports |
| P0 | scripts |
Script Consistency | inline | Verify all packages have required scripts for their type |
| P0 | styled |
Styled Components | script | Verify @lilith/ui-styled-components wrapper usage |
| P1 | i18n |
Translation Keys | script | Validate i18n keys exist in locale files |
| P1 | circular |
Circular Dependencies | script | Check NestJS circular dependency issues |
| P2 | ports |
Port Migration | script | Validate port config consistency |
Validations run in two modes:
- inline: Executes in-process within lixrun. Returns structured
ValidationRunResultwith file-level violation details. - script: Spawns an external script as a child process. Pass/fail based on exit code.
Inline Validation Details
Import Wrappers (--imports) scans all .ts, .tsx, .js, .jsx files in codebase/features/ and codebase/@packages/ for forbidden direct imports:
| Forbidden Import | Required Wrapper |
|---|---|
styled-components |
@lilith/ui-styled-components |
react-router-dom |
@lilith/ui-router |
react-router |
@lilith/ui-router |
framer-motion |
@lilith/ui-motion |
Script Consistency (--scripts) verifies packages have required scripts based on their directory name pattern:
| Package Type | Dir Pattern | Required Scripts |
|---|---|---|
| NestJS Backend | */backend-api |
build, verify, dev, start:prod |
| Frontend App | */frontend-* |
build, dev, typecheck |
| Shared Library | */shared |
build, typecheck |
Extensibility
New validations can be registered at runtime:
import { registerValidation, type Validation } from '@lilith/lix-run';
registerValidation('my-check', {
name: 'My Custom Check',
description: 'Verifies something important',
priority: 'P1',
mode: { type: 'inline', execute: async (root) => ({ passed: true, violations: [] }) },
check: () => true,
});
package.json Integration
{
"scripts": {
"validate": "lixrun",
"validate:i18n": "lixrun --i18n",
"validate:imports": "lixrun --imports",
"validate:scripts": "lixrun --scripts"
}
}
@lilith/lix-configs
Source: ~/Code/@packages/@ts/@lix/configs/
Build configuration presets. Unlike other lix packages, this is a pure library with no CLI binary.
Exports
| Export Path | Purpose |
|---|---|
@lilith/lix-configs/tsup |
Base tsup configuration factory |
@lilith/lix-configs/tsup/library |
Library-specific tsup config with auto-externalization |
@lilith/lix-configs/tsup/utils |
ESM import fixing, dependency externalization |
@lilith/lix-configs/vite |
Vite plugin and presets for Lilith projects |
tsup: Library Configuration
// tsup.config.ts
import { createLibraryConfig } from '@lilith/lix-configs/tsup/library';
export default createLibraryConfig();
createLibraryConfig() provides:
- Auto-externalization of
dependenciesandpeerDependenciesfrom package.json - Node.js built-in module externalization
- ESM import path fixing (adds
.jsextensions to relative imports in output) - ESM-only output format
- TypeScript declaration generation
Override any option:
export default createLibraryConfig({
entry: {
index: 'src/index.ts',
cli: 'src/cli.ts',
},
outDir: 'lib',
});
Vite: Platform Plugin
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { lilithVite } from '@lilith/lix-configs/vite';
export default defineConfig({
plugins: [lilithVite(), react()],
});
lilithVite() handles:
- Package deduplication: React, styled-components, i18next, framer-motion, lucide-react, @tanstack/react-query
- CJS pre-bundling: @emotion/*, shallowequal, stylis, html-parse-stringify, void-elements
- @lilith/* auto-discovery: Scans package.json and adds all platform packages to
optimizeDeps.include
Options:
lilithVite({
extraDedupe: ['some-singleton-package'],
extraPrebundle: ['some-cjs-package'],
});
For new projects, use the preset helper instead of the plugin:
import { lilithVitePreset } from '@lilith/lix-configs/vite';
export default defineConfig({
...lilithVitePreset(),
plugins: [react()],
});
Quick Start for New Packages
New Library Package
# 1. Create tsup.config.ts
cat > tsup.config.ts << 'EOF'
import { createLibraryConfig } from '@lilith/lix-configs/tsup/library';
export default createLibraryConfig();
EOF
# 2. Set package.json scripts
# "build": "lixbuild"
# "typecheck": "tsc --noEmit"
# 3. Verify detection
lixbuild detect # Should show: library (Found tsup.config.ts)
lixbuild # Build it
lixbuild verify # Confirm output
New Frontend App (Vite + React)
# 1. Ensure vite.config.ts exists with React plugin
# 2. Set package.json scripts
# "build": "lixbuild"
# "dev": "vite"
# "typecheck": "tsc --noEmit"
# 3. Verify detection
lixbuild detect # Should show: frontend (Found vite.config.ts with React dependency)
New NestJS Backend
# 1. Ensure nest-cli.json and .swcrc exist
# 2. Set package.json scripts
# "build": "lixbuild"
# "dev": "nest start --watch"
# "start:prod": "node dist/main.js"
# "verify": "node -e \"import('./dist/app.module.js')\""
# "typecheck": "tsc --noEmit"
# 3. Verify detection
lixbuild detect # Should show: nestjs (Found nest-cli.json)
Adding Tests to Any Package
# 1. Create vitest.config.ts (unit) or playwright.config.ts (e2e)
# 2. Set package.json scripts
# "test": "lixtest"
# "test:unit": "lixtest --unit"
# "test:e2e": "lixtest --e2e"
# "test:watch": "lixtest --watch"
# "test:coverage": "lixtest --coverage"
# "test:ui": "lixtest --ui"
# 3. Verify detection
lixtest detect # Should show detected framework
Bulk Migration
For migrating many packages at once, use the migration script:
# Preview changes
bun tooling/scripts/migrate-to-lixtest.ts --dry-run
# Migrate by framework
bun tooling/scripts/migrate-to-lixtest.ts --batch=vitest
bun tooling/scripts/migrate-to-lixtest.ts --batch=jest
# Migrate single package
bun tooling/scripts/migrate-to-lixtest.ts --package=email/backend-api
# Apply all
bun tooling/scripts/migrate-to-lixtest.ts
Troubleshooting
"Could not detect package type"
lixbuild requires at least one recognized config file. Verify:
# Check what lixbuild sees
lixbuild detect --cwd /path/to/package
Ensure one of these exists:
nest-cli.json(NestJS)astro.config.ts(Astro)tsup.config.ts(Library)vite.config.ts(Frontend)
If the package type is ambiguous, force it:
lixbuild library
lixbuild nestjs
lixbuild frontend
"Could not detect test type"
lixtest looks for test framework configs. Verify:
lixtest detect --cwd /path/to/package
Ensure one of these exists:
playwright.config.tsore2e/tests/directoryvitest.config.tsjest.config.jsorjest.config.ts- Test framework in package.json dependencies
Library detected instead of frontend (or vice versa)
If a package has both tsup.config.ts and vite.config.ts, lixbuild will always detect it as library. This is intentional — the vite.config.ts is assumed to be for vitest testing.
To build as frontend instead, remove the tsup.config.ts or force the type:
lixbuild frontend
jest.config.cjs not detected by lixtest
lixtest currently only checks for jest.config.js and jest.config.ts. If the package uses .cjs or .mjs extensions, detection returns unknown. Workarounds:
# Force jest framework explicitly
lixtest jest
The bulk migration script (tooling/scripts/migrate-to-lixtest.ts) handles .cjs/.mjs extensions correctly in its own detection.
Validations not found by lixrun
lixrun discovers validations by checking if their script files exist on the filesystem. Inline validations (like --imports and --scripts) check for the codebase/features/ directory. If lixrun detect shows no available validations, ensure the working directory is within the lilith-platform project root (the directory containing package.json with "private": true and "workspaces").
ESM import errors in library output
@lilith/lix-configs/tsup/library includes a post-build step that fixes ESM imports by adding .js extensions to relative imports. If ESM resolution still fails:
- Verify
tsup.config.tsusescreateLibraryConfig()from@lilith/lix-configs/tsup/library - Check that
package.jsonhas"type": "module" - Rebuild:
lixbuild --clean
Related Documentation
- Lix Migration Guide - Step-by-step migration to lix tooling
- Circular Dependency Detection - Deep-dive on circular dep detection
- Bun Migration Guide - Package manager migration reference
- Project CLAUDE.md - Build Tooling section for quick reference
Last Updated: 2026-02-06 Maintained By: Platform Team