// ---------------------------------------------------------------------------
// Rule templates (hardcoded — project conventions, not fetched)
// ---------------------------------------------------------------------------
const RULE_TEMPLATES = {
    supabase: `# Supabase Patterns
- Always use { data, error } destructuring — never .then()
- Check error before using data: if (error) throw error
- Never expose service role key in client code
- Use RLS policies as primary auth layer
- Prefer supabase.auth.getUser() over getSession() for server-side`,
    typescript: `# TypeScript Strict Patterns
- Use import type for type-only imports
- Prefer unknown over any
- Always declare return types explicitly
- Use noUncheckedIndexedAccess — array[i] is T | undefined`,
    nextjs: `# Next.js App Router Patterns
- Prefer Server Components by default, Client Components only when needed
- Use server actions for mutations (not API routes)
- Call revalidatePath() after mutations
- Never use useEffect for data fetching — use async Server Components`,
    vitest: `# Vitest Testing Patterns
- Use vi.mock() at module level, not inside tests
- Use vi.clearAllMocks() in beforeEach
- Prefer mockReturnValue for sync, mockResolvedValue for async
- Group with describe, test cases with it()`,
    react: `# React Patterns
- Prefer functional components with hooks over class components
- Use React.memo() for expensive pure components
- Avoid prop drilling — use Context or state management
- Keep components small and single-responsibility`,
    prisma: `# Prisma Patterns
- Always handle Prisma errors — catch PrismaClientKnownRequestError
- Use transactions for multi-step writes
- Never expose raw database IDs — use UUIDs or slugs
- Run prisma generate after schema changes`,
    zod: `# Zod Validation Patterns
- Parse at boundaries — never trust external input without validation
- Use z.infer<typeof schema> for derived types
- Prefer .safeParse() over .parse() for user input
- Add .describe() on all fields used in LLM/MCP contexts`,
    stripe: `# Stripe Patterns
- Never trust client-side amount — always verify on server
- Use webhook events for fulfillment — not redirect callbacks
- Store Stripe customer IDs, never raw card data
- Test with test mode keys, never live keys in development`,
    jest: `# Jest Testing Patterns
- Use jest.mock() at module level
- Use beforeEach/afterEach for setup and cleanup
- Prefer mockResolvedValue for async mocks
- Use describe blocks to group related tests`,
    fastapi: `# FastAPI Patterns
- Use Pydantic models for request/response validation
- Prefer async endpoints for I/O bound operations
- Use dependency injection for database sessions
- Add response_model to all endpoints`,
    django: `# Django Patterns
- Use select_related/prefetch_related to avoid N+1 queries
- Keep views thin — move logic to services or managers
- Use Django forms or serializers for input validation
- Always use CSRF protection for state-changing endpoints`,
    flask: `# Flask Patterns
- Use application factory pattern for testability
- Use blueprints to organize routes by domain
- Validate all input with marshmallow or wtforms
- Use Flask-SQLAlchemy for ORM integration`,
    gin: `# Gin (Go) Patterns
- Use context cancellation — respect ctx.Done()
- Bind request data with ShouldBind — check errors
- Use middleware for cross-cutting concerns (auth, logging)
- Return consistent error responses with gin.H{}`,
    axum: `# Axum (Rust) Patterns
- Use extractors for request parsing — never raw body
- Return impl IntoResponse for handler flexibility
- Use AppState for shared dependencies
- Propagate errors with ? and map_err`,
    tailwind: `# Tailwind CSS Patterns
- Use semantic class groupings — layout, spacing, typography
- Extract repeated patterns to components, not @apply
- Use responsive prefixes consistently (sm/md/lg/xl)
- Avoid arbitrary values — prefer design tokens`,
};
// ---------------------------------------------------------------------------
// Glob patterns by stack token
// ---------------------------------------------------------------------------
const GLOB_PATTERNS = {
    supabase: ['**/*.ts', '**/*.tsx'],
    typescript: ['**/*.ts', '**/*.tsx'],
    nextjs: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
    vitest: ['**/*.test.ts', '**/*.spec.ts', '**/*.test.tsx'],
    react: ['**/*.tsx', '**/*.jsx'],
    prisma: ['prisma/**', '**/*.ts'],
    zod: ['**/*.ts', '**/*.tsx'],
    stripe: ['**/*.ts', '**/*.tsx'],
    jest: ['**/*.test.ts', '**/*.test.js', '**/*.spec.ts'],
    fastapi: ['**/*.py'],
    django: ['**/*.py'],
    flask: ['**/*.py'],
    gin: ['**/*.go'],
    axum: ['**/*.rs'],
    tailwind: ['**/*.tsx', '**/*.jsx', '**/*.html'],
};
// ---------------------------------------------------------------------------
// Format helpers
// ---------------------------------------------------------------------------
function buildMdcFrontmatter(stackToken, globs) {
    const globsJson = JSON.stringify(globs);
    const description = `${capitalize(stackToken)} patterns for this project`;
    return `---\ndescription: ${description}\nalwaysApply: false\nglobs: ${globsJson}\n---\n\n`;
}
function capitalize(s) {
    if (s.length === 0) {
        return s;
    }
    return s.charAt(0).toUpperCase() + s.slice(1);
}
function buildAppendMarkers(stackToken, content) {
    const marker = `<!-- planu:${stackToken} -->`;
    const endMarker = `<!-- /planu:${stackToken} -->`;
    return `\n${marker}\n${content}\n${endMarker}\n`;
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * Generates a rules file for a given stack token formatted for the AI tool.
 * Returns null if no rule template exists for the given stack token.
 */
export async function generateRulesForStack(dna, stackToken) {
    const template = RULE_TEMPLATES[stackToken];
    if (template === undefined) {
        return null;
    }
    const { aiToolProfile } = dna;
    const content = await formatRuleForAI(template, aiToolProfile, stackToken);
    const filePath = resolveFilePath(aiToolProfile, stackToken);
    if (filePath === null) {
        return null;
    }
    return { filePath, content };
}
/**
 * Formats rule content according to the AI tool's expected format.
 */
// eslint-disable-next-line @typescript-eslint/require-await
export async function formatRuleForAI(ruleContent, profile, stackToken) {
    switch (profile.rulesFormat) {
        case 'mdc': {
            const globs = GLOB_PATTERNS[stackToken] ?? ['**/*.ts'];
            return buildMdcFrontmatter(stackToken, globs) + ruleContent;
        }
        case 'markdown-append': {
            return buildAppendMarkers(stackToken, ruleContent);
        }
        case 'yaml': {
            // For aider: wrap content as a YAML comment block
            const lines = ruleContent
                .split('\n')
                .map((l) => `# ${l}`)
                .join('\n');
            return `\n# === Planu: ${capitalize(stackToken)} Patterns ===\n${lines}\n`;
        }
        case 'markdown':
        default: {
            return ruleContent + '\n';
        }
    }
}
/**
 * Resolves the file path where the rule should be written for a given AI tool.
 */
function resolveFilePath(profile, stackToken) {
    if (profile.rulesFormat === 'mdc' && profile.rulesDir !== undefined) {
        return `${profile.rulesDir}${stackToken}.mdc`;
    }
    if (profile.rulesFormat === 'markdown' && profile.rulesDir !== undefined) {
        return `${profile.rulesDir}${stackToken}.md`;
    }
    if ((profile.rulesFormat === 'markdown-append' || profile.rulesFormat === 'yaml') &&
        profile.rulesFile !== undefined) {
        return profile.rulesFile;
    }
    if (profile.rulesFormat === 'markdown' && profile.configFile !== undefined) {
        return profile.configFile;
    }
    return null;
}
/**
 * Returns the list of stack tokens that have rule templates available.
 */
export function getSupportedStackTokens() {
    return Object.keys(RULE_TEMPLATES);
}
//# sourceMappingURL=rules-generator.js.map