dxai-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,769 @@
1
+ // ── Tech Stack Registry ──
2
+
3
+ export const TECH_STACKS = [
4
+ { id: 'react', name: 'React', label: 'React / Next.js / TypeScript' },
5
+ { id: 'vue', name: 'Vue', label: 'Vue / Nuxt' },
6
+ { id: 'svelte', name: 'Svelte', label: 'Svelte / SvelteKit' },
7
+ { id: 'python', name: 'Python', label: 'Python / FastAPI / Django' },
8
+ { id: 'node', name: 'Node.js', label: 'Node.js / Express' },
9
+ { id: 'go', name: 'Go', label: 'Go / Gin / Echo' },
10
+ { id: 'rust', name: 'Rust', label: 'Rust' },
11
+ { id: 'mobile', name: 'Mobile', label: 'React Native / Flutter' },
12
+ ];
13
+
14
+ // ── Agent Rules — Universal + Per-Stack ──
15
+
16
+ const AGENT_RULES = {
17
+ universal: {
18
+ code_quality: [
19
+ 'No `any` in TypeScript. Use `unknown` + type guards.',
20
+ 'No barrel files (index.ts re-exports). Import from source.',
21
+ 'Functions over 40 lines need splitting.',
22
+ 'No magic numbers/strings. Extract to named constants.',
23
+ 'Dead code gets deleted, not commented out.',
24
+ 'No default exports except where frameworks require them (pages/routes).',
25
+ 'Match existing code patterns. Read 2-3 similar files before generating new ones.',
26
+ 'No placeholder implementations (TODO, "implement this", empty function bodies).',
27
+ ],
28
+ error_handling: [
29
+ 'Every catch block must recover, rethrow with context, or log + return typed error. No empty catches.',
30
+ 'User-facing errors get human-readable messages. Internal errors get structured logging.',
31
+ 'API boundaries validate all input. Trust nothing from outside your system boundary.',
32
+ 'Never swallow errors silently. If you catch it, handle it.',
33
+ ],
34
+ anti_patterns: [
35
+ 'No `eslint-disable` or `@ts-ignore` without an explaining comment.',
36
+ 'No `console.log` for debugging in committed code.',
37
+ 'No hardcoded URLs, ports, secrets, or environment-specific values.',
38
+ 'No catching errors just to re-throw without context.',
39
+ 'No God objects or junk-drawer util files.',
40
+ 'No string concatenation for SQL, HTML, or shell commands.',
41
+ 'No commented-out code blocks. Delete or use version control.',
42
+ 'No `// TODO` without a linked issue or ticket number.',
43
+ ],
44
+ testing: [
45
+ 'Test behavior, not implementation. Tests survive refactors.',
46
+ 'Every bug fix gets a regression test before the fix.',
47
+ 'Mock at system boundaries (HTTP, DB, filesystem), not between internal modules.',
48
+ 'Test names describe scenarios: "returns 404 when user not found", not "test getUserById".',
49
+ ],
50
+ git: [
51
+ 'Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, `test:`.',
52
+ 'One logical change per commit. Never mix refactoring with features.',
53
+ 'PR descriptions explain WHY, not just WHAT.',
54
+ ],
55
+ },
56
+ stacks: {
57
+ react: {
58
+ rules: [
59
+ 'Server Components by default. `"use client"` only for hooks, event handlers, browser APIs.',
60
+ 'No prop drilling past 2 levels. Use composition or context.',
61
+ '`useEffect` is for synchronization, not data fetching. Use server components, server actions, or React Query.',
62
+ 'No `index` as key for dynamic lists. Use stable unique IDs.',
63
+ 'Co-locate: `Button.tsx`, `Button.test.tsx`, styles in one directory.',
64
+ 'Type all props with interfaces. Export prop types for reusable components.',
65
+ 'Zod for all runtime validation (forms, API responses).',
66
+ 'Prefer Tailwind CSS utility classes over custom CSS.',
67
+ ],
68
+ anti_patterns: [
69
+ 'No `useEffect` for derived state — use `useMemo`.',
70
+ 'No wrapping everything in `React.memo` without profiling first.',
71
+ 'No API calls directly in components — use server components, server actions, or data hooks.',
72
+ 'No class components. Functional components with hooks only.',
73
+ 'No `<div>` soup. Use semantic HTML elements.',
74
+ ],
75
+ },
76
+ vue: {
77
+ rules: [
78
+ 'Composition API with `<script setup>` only. No Options API.',
79
+ 'TypeScript strict mode in all `.vue` and `.ts` files.',
80
+ 'Use `defineProps` and `defineEmits` with type-only syntax.',
81
+ 'Pinia for state management. No Vuex.',
82
+ 'Nuxt: use `useFetch`/`useAsyncData` for data fetching, not raw `fetch` in components.',
83
+ 'Component naming: PascalCase for SFCs, kebab-case in templates.',
84
+ 'Use VueUse composables before writing custom ones.',
85
+ ],
86
+ anti_patterns: [
87
+ 'No Options API (`data()`, `methods`, `computed` as options).',
88
+ 'No direct DOM manipulation — use template refs.',
89
+ 'No Vuex in new code. Use Pinia.',
90
+ 'No `v-html` with user-provided content (XSS risk).',
91
+ ],
92
+ },
93
+ svelte: {
94
+ rules: [
95
+ 'TypeScript in all Svelte components and modules.',
96
+ 'Use `$state`, `$derived`, `$effect` runes (Svelte 5).',
97
+ 'Form actions for mutations, load functions for data.',
98
+ 'Keep components small — extract logic into `.ts` modules.',
99
+ 'Use `+layout.server.ts` for shared data loading.',
100
+ 'SvelteKit for all new projects.',
101
+ ],
102
+ anti_patterns: [
103
+ 'No Svelte 4 reactive declarations (`$:`) — use Svelte 5 runes.',
104
+ 'No client-side data fetching in `+page.svelte` — use `+page.ts` or `+page.server.ts`.',
105
+ 'No `onMount` for data loading — use load functions.',
106
+ ],
107
+ },
108
+ python: {
109
+ rules: [
110
+ 'Type hints on every function signature.',
111
+ 'Pydantic models for all external data. No raw dicts for structured data.',
112
+ '`pathlib.Path` not `os.path`. f-strings not `.format()`.',
113
+ 'Python 3.11+ features: match statements, `ExceptionGroup`, `TaskGroup`.',
114
+ 'FastAPI: dependency injection, `response_model` on all endpoints.',
115
+ 'pytest with fixtures, parametrize, and conftest.py.',
116
+ 'Ruff for linting and formatting.',
117
+ 'async/await for IO-bound operations (httpx, databases, file ops).',
118
+ ],
119
+ anti_patterns: [
120
+ 'No bare `except:` — always specify the exception type.',
121
+ 'No mutable default arguments (`def f(x=[])`).',
122
+ 'No `from module import *`.',
123
+ 'No `os.path` — use `pathlib`.',
124
+ 'No global state or module-level side effects.',
125
+ ],
126
+ },
127
+ node: {
128
+ rules: [
129
+ 'Validate all external input at API boundaries with Zod/Joi.',
130
+ 'Dependency injection. No importing DB clients directly in handlers.',
131
+ 'All env config loaded once at startup via validated schema. No scattered `process.env.X`.',
132
+ 'ES modules only (`import`/`export`). No CommonJS `require()`.',
133
+ 'Structured logging with Pino or Winston. No `console.log` in production.',
134
+ 'async/await only. No raw callbacks or `.then()` chains.',
135
+ 'Express: middleware pattern, router modules, centralized error handlers.',
136
+ 'Database: Drizzle ORM or Prisma with migrations.',
137
+ ],
138
+ anti_patterns: [
139
+ 'No `require()` — use ESM imports.',
140
+ 'No nested callbacks (callback hell).',
141
+ 'No swallowing errors with generic 500 responses. Return typed errors.',
142
+ 'No `any` types. TypeScript strict mode.',
143
+ 'No synchronous filesystem operations in request handlers.',
144
+ ],
145
+ },
146
+ go: {
147
+ rules: [
148
+ 'Always check errors. Use `fmt.Errorf` with `%w` for wrapping.',
149
+ 'Standard project layout: `cmd/`, `internal/`, `pkg/`.',
150
+ 'Interfaces for dependency injection and testability.',
151
+ 'Use `context.Context` for cancellation and deadlines.',
152
+ 'Table-driven tests with `t.Run()` subtests.',
153
+ 'Structured logging with `slog` (stdlib) or `zerolog`.',
154
+ 'golangci-lint with project `.golangci.yml` config.',
155
+ 'Go 1.22+ features: range over int, enhanced routing patterns.',
156
+ ],
157
+ anti_patterns: [
158
+ 'No `panic` for expected error cases — return errors.',
159
+ 'No `interface{}` — use `any` (Go 1.18+) or typed generics.',
160
+ 'No `init()` functions unless absolutely necessary.',
161
+ 'No global mutable state. Pass dependencies explicitly.',
162
+ ],
163
+ },
164
+ rust: {
165
+ rules: [
166
+ 'Prefer `Result<T, E>` over `unwrap()`. Handle errors properly.',
167
+ '`thiserror` for library errors, `anyhow` for application errors.',
168
+ 'Axum or Actix-web for HTTP services.',
169
+ '`serde` for all serialization/deserialization.',
170
+ 'Clippy: run with `--all-targets -- -D warnings`.',
171
+ 'Unit tests in same file (`#[cfg(test)]`), integration tests in `tests/` directory.',
172
+ 'Rust 2021 edition or later.',
173
+ ],
174
+ anti_patterns: [
175
+ 'No `.unwrap()` or `.expect()` in library/production code — propagate errors with `?`.',
176
+ 'No `clone()` to satisfy the borrow checker without understanding why.',
177
+ 'No `unsafe` blocks without a `// SAFETY:` comment explaining the invariant.',
178
+ 'No manual `Drop` implementations unless managing raw resources.',
179
+ ],
180
+ },
181
+ mobile: {
182
+ rules: [
183
+ 'React Native: Expo for new projects, bare workflow only when needed.',
184
+ 'React Native: React Navigation v7+ for routing.',
185
+ 'React Native: Zustand or React Query for state management.',
186
+ 'Flutter: BLoC pattern or Riverpod for state management.',
187
+ 'Flutter: `freezed` for immutable data classes.',
188
+ 'Test on both iOS and Android before PR.',
189
+ 'Handle offline states and loading states gracefully.',
190
+ 'Platform-specific code isolated behind abstraction layers.',
191
+ ],
192
+ anti_patterns: [
193
+ 'No platform-specific code scattered across the codebase — isolate it.',
194
+ 'No blocking the UI thread with heavy computations.',
195
+ 'No hardcoded pixel values — use responsive/adaptive layouts.',
196
+ 'No ignoring platform design guidelines (Material on Android, HIG on iOS).',
197
+ ],
198
+ },
199
+ },
200
+ };
201
+
202
+ // ── Cursor Rules — Tightened ──
203
+
204
+ export const CURSOR_RULES = {
205
+ general: `---
206
+ description: General development best practices
207
+ globs: "**/*"
208
+ alwaysApply: true
209
+ ---
210
+
211
+ # General Rules
212
+
213
+ - Plan before coding. For multi-file changes, list all files first.
214
+ - Run tests after every change. Not done until green.
215
+ - No empty catches. No silent failures. Handle all errors with context.
216
+ - No \`any\` types. No \`eslint-disable\` without justification. No \`console.log\` in committed code.
217
+ - Dead code gets deleted, not commented out.
218
+ - Conventional commits: \`feat:\`, \`fix:\`, \`chore:\`, one logical change per commit.
219
+ - Match existing patterns. Read 2-3 similar files before generating new ones.
220
+ - Use \`context7\` to look up library APIs — do not guess.
221
+ `,
222
+
223
+ react: `---
224
+ description: React and Next.js development rules
225
+ globs: "**/*.{tsx,jsx,ts,js}"
226
+ alwaysApply: true
227
+ ---
228
+
229
+ # React / Next.js Rules
230
+
231
+ - Use functional components with hooks (no class components)
232
+ - Server Components by default in Next.js App Router
233
+ - Add "use client" directive only when hooks or interactivity is needed
234
+ - Use TypeScript strict mode — no \`any\` types
235
+ - Colocate components: component, styles, tests in same directory
236
+ - Use React.memo() and useMemo/useCallback only when profiling shows need
237
+ - Prefer Tailwind CSS utility classes over custom CSS
238
+ - Use shadcn/ui or Radix primitives for accessible UI components
239
+ - Next.js: use metadata API for SEO, not <Head>
240
+ - Next.js: use Image component with proper width/height
241
+ - Next.js: prefer Server Actions over API routes for form mutations
242
+ - Zod for all runtime validation (forms, API responses)
243
+ - State management: React Context for simple state, Zustand for complex
244
+
245
+ # DO NOT
246
+
247
+ - No \`useEffect\` for derived state — use \`useMemo\`
248
+ - No \`index\` as key for dynamic lists — use stable unique IDs
249
+ - No API calls directly in components — use server actions or data hooks
250
+ - No prop drilling past 2 levels — use composition or context
251
+ - No wrapping everything in \`React.memo\` without profiling first
252
+ `,
253
+
254
+ vue: `---
255
+ description: Vue and Nuxt development rules
256
+ globs: "**/*.{vue,ts,js}"
257
+ alwaysApply: true
258
+ ---
259
+
260
+ # Vue / Nuxt Rules
261
+
262
+ - Use Composition API with <script setup> (no Options API)
263
+ - TypeScript with strict mode in all .vue and .ts files
264
+ - Use defineProps and defineEmits with type-only syntax
265
+ - Prefer Pinia for state management
266
+ - Use auto-imports for Vue APIs and composables
267
+ - Nuxt: use useFetch/useAsyncData for data fetching
268
+ - Nuxt: use definePageMeta for page-level metadata
269
+ - Component naming: PascalCase for SFCs, kebab-case in templates
270
+ - Use VueUse composables before writing custom ones
271
+
272
+ # DO NOT
273
+
274
+ - No Options API (\`data()\`, \`methods\`, \`computed\` as options)
275
+ - No Vuex in new code — use Pinia
276
+ - No direct DOM manipulation — use template refs
277
+ - No \`v-html\` with user-provided content (XSS risk)
278
+ `,
279
+
280
+ svelte: `---
281
+ description: Svelte and SvelteKit development rules
282
+ globs: "**/*.{svelte,ts,js}"
283
+ alwaysApply: true
284
+ ---
285
+
286
+ # Svelte / SvelteKit Rules
287
+
288
+ - Use TypeScript in all Svelte components and modules
289
+ - Prefer SvelteKit for all new projects
290
+ - Use $state, $derived, $effect runes (Svelte 5)
291
+ - Use form actions for mutations, load functions for data
292
+ - Keep components small — extract logic into .ts modules
293
+ - Use +layout.server.ts for shared data loading
294
+
295
+ # DO NOT
296
+
297
+ - No Svelte 4 reactive declarations (\`$:\`) — use Svelte 5 runes
298
+ - No client-side data fetching in \`+page.svelte\` — use load functions
299
+ - No \`onMount\` for data loading — use \`+page.ts\` or \`+page.server.ts\`
300
+ `,
301
+
302
+ python: `---
303
+ description: Python development rules
304
+ globs: "**/*.py"
305
+ alwaysApply: true
306
+ ---
307
+
308
+ # Python Rules
309
+
310
+ - Use Python 3.11+ features (match statements, ExceptionGroup, etc.)
311
+ - Type hints on all function signatures — use \`from typing import\` as needed
312
+ - Pydantic v2 for data validation and settings management
313
+ - FastAPI: use dependency injection, not global state
314
+ - FastAPI: always define response_model on endpoints
315
+ - Django: use class-based views, custom managers, and signals appropriately
316
+ - Use async/await where IO-bound (httpx, databases, file ops)
317
+ - pytest for testing — use fixtures, parametrize, and conftest.py
318
+ - Ruff for linting and formatting (replaces flake8 + black + isort)
319
+ - Use virtual environments (venv or uv) — never install globally
320
+
321
+ # DO NOT
322
+
323
+ - No bare \`except:\` — always specify the exception type
324
+ - No mutable default arguments (\`def f(x=[])\`)
325
+ - No \`from module import *\`
326
+ - No \`os.path\` — use \`pathlib.Path\`
327
+ - No global state or module-level side effects
328
+ `,
329
+
330
+ node: `---
331
+ description: Node.js backend development rules
332
+ globs: "**/*.{ts,js,mts,mjs}"
333
+ alwaysApply: true
334
+ ---
335
+
336
+ # Node.js Rules
337
+
338
+ - TypeScript with strict mode for all backend code
339
+ - Use ES modules (import/export) — no CommonJS require()
340
+ - Express: use middleware pattern, router modules, error handlers
341
+ - Validate all input with Zod or Joi at API boundaries
342
+ - Use async/await — never raw callbacks or .then() chains
343
+ - Environment variables: load once at startup via validated schema, no scattered \`process.env.X\`
344
+ - Use Winston or Pino for structured logging (not console.log in prod)
345
+ - Database: use Drizzle ORM or Prisma with migrations
346
+ - Tests: Vitest or Jest with supertest for API testing
347
+ - Docker: multi-stage builds, non-root user, .dockerignore
348
+
349
+ # DO NOT
350
+
351
+ - No \`require()\` — use ESM imports
352
+ - No nested callbacks (callback hell)
353
+ - No swallowing errors with generic 500 responses — return typed errors
354
+ - No synchronous filesystem operations in request handlers
355
+ - No importing DB clients directly in handlers — use dependency injection
356
+ `,
357
+
358
+ go: `---
359
+ description: Go development rules
360
+ globs: "**/*.go"
361
+ alwaysApply: true
362
+ ---
363
+
364
+ # Go Rules
365
+
366
+ - Use Go 1.22+ features (range over int, enhanced routing)
367
+ - Follow standard project layout (cmd/, internal/, pkg/)
368
+ - Error handling: always check errors, use fmt.Errorf with %w for wrapping
369
+ - Use interfaces for dependency injection and testability
370
+ - Gin or Echo for HTTP APIs — use middleware pattern
371
+ - Use context.Context for cancellation and deadlines
372
+ - Table-driven tests with t.Run() subtests
373
+ - Use golangci-lint with a .golangci.yml config
374
+ - Structured logging with slog (stdlib) or zerolog
375
+
376
+ # DO NOT
377
+
378
+ - No \`panic\` for expected error cases — return errors
379
+ - No \`interface{}\` — use \`any\` (Go 1.18+) or typed generics
380
+ - No \`init()\` functions unless absolutely necessary
381
+ - No global mutable state — pass dependencies explicitly
382
+ `,
383
+
384
+ rust: `---
385
+ description: Rust development rules
386
+ globs: "**/*.rs"
387
+ alwaysApply: true
388
+ ---
389
+
390
+ # Rust Rules
391
+
392
+ - Use Rust 2021 edition or later
393
+ - Prefer Result<T, E> over unwrap() — handle errors properly
394
+ - Use thiserror for library errors, anyhow for application errors
395
+ - Axum or Actix-web for HTTP services
396
+ - Use serde for serialization/deserialization
397
+ - Clippy: run with --all-targets -- -D warnings
398
+ - Tests: unit tests in same file, integration tests in tests/ directory
399
+
400
+ # DO NOT
401
+
402
+ - No \`.unwrap()\` or \`.expect()\` in library/production code — use \`?\`
403
+ - No \`clone()\` to satisfy the borrow checker without understanding why
404
+ - No \`unsafe\` blocks without a \`// SAFETY:\` comment
405
+ - No manual \`Drop\` implementations unless managing raw resources
406
+ `,
407
+
408
+ mobile: `---
409
+ description: Mobile development rules
410
+ globs: "**/*.{tsx,jsx,ts,js,dart}"
411
+ alwaysApply: true
412
+ ---
413
+
414
+ # Mobile Development Rules
415
+
416
+ - React Native: use Expo for new projects, bare workflow only when needed
417
+ - React Native: use React Navigation v7+ for routing
418
+ - React Native: use Zustand or React Query for state
419
+ - Flutter: follow BLoC pattern or Riverpod for state management
420
+ - Flutter: use freezed for immutable data classes
421
+ - Always test on both iOS and Android before PR
422
+ - Handle offline states and loading states gracefully
423
+ - Platform-specific code isolated behind abstraction layers
424
+
425
+ # DO NOT
426
+
427
+ - No platform-specific code scattered across the codebase — isolate it
428
+ - No blocking the UI thread with heavy computations
429
+ - No hardcoded pixel values — use responsive/adaptive layouts
430
+ - No ignoring platform design guidelines (Material on Android, HIG on iOS)
431
+ `,
432
+ };
433
+
434
+ // Cursor commands templates
435
+ export const CURSOR_COMMANDS = {
436
+ pr: `# Create Pull Request
437
+
438
+ 1. Look at all staged and unstaged changes with \`git diff\`
439
+ 2. Write a clear commit message following conventional commits format
440
+ 3. Stage all changes and commit
441
+ 4. Push to the current branch
442
+ 5. Use \`gh pr create\` to open a PR with a descriptive title and body
443
+ 6. Return the PR URL when done
444
+ `,
445
+
446
+ 'fix-issue': `# Fix GitHub Issue
447
+
448
+ 1. Accept an issue number as input
449
+ 2. Fetch the issue details using \`gh issue view\`
450
+ 3. Analyze the issue description and any linked code
451
+ 4. Find the relevant files in the codebase
452
+ 5. Implement the fix following project conventions
453
+ 6. Write tests for the fix
454
+ 7. Run the test suite to verify
455
+ 8. Create a PR that references the issue with "Fixes #<number>"
456
+ `,
457
+
458
+ review: `# Code Review
459
+
460
+ 1. Run the linter on all changed files
461
+ 2. Run the full test suite
462
+ 3. Check for common issues:
463
+ - Unused imports or variables
464
+ - Missing error handling
465
+ - Missing TypeScript types
466
+ - Hardcoded values that should be config
467
+ - Console.log statements that should be removed
468
+ - Missing tests for new functionality
469
+ 4. Summarize findings with severity levels (critical, warning, suggestion)
470
+ `,
471
+
472
+ 'test-all': `# Run All Tests
473
+
474
+ 1. Detect the test framework being used (jest, vitest, pytest, go test, etc.)
475
+ 2. Run the full test suite
476
+ 3. If any tests fail, analyze the failures
477
+ 4. Suggest fixes for failing tests
478
+ 5. Provide a summary of test results
479
+ `,
480
+
481
+ refactor: `# Refactor Module
482
+
483
+ 1. Accept a file or directory path as input
484
+ 2. Analyze the current code structure
485
+ 3. Identify code smells: duplication, long functions, deep nesting, etc.
486
+ 4. Propose a refactoring plan
487
+ 5. Wait for approval before proceeding
488
+ 6. Implement the refactoring step by step
489
+ 7. Run tests after each step to ensure nothing breaks
490
+ 8. Provide a before/after summary
491
+ `,
492
+ };
493
+
494
+ // ── Contextual Rules — Maturity-Aware ──
495
+
496
+ const CONTEXTUAL_RULES = {
497
+ greenfield: {
498
+ code_quality: [
499
+ 'Set up directory structure following framework conventions before writing features.',
500
+ 'Configure linting and formatting from day one.',
501
+ 'Set up CI pipeline early — even a basic lint + test workflow.',
502
+ ],
503
+ testing: [
504
+ 'Set up test infrastructure immediately: framework, config, first smoke test.',
505
+ 'High coverage is cheaper to build from the start than to add retroactively.',
506
+ ],
507
+ git: [
508
+ 'Set up branch protection and PR templates early.',
509
+ ],
510
+ },
511
+ early: {
512
+ code_quality: [
513
+ 'Establish and document patterns early — they become the standard.',
514
+ 'Configure linting and formatting before the codebase grows.',
515
+ ],
516
+ testing: [
517
+ 'Set up test infrastructure now. Coverage debt compounds fast.',
518
+ 'Write tests for core paths before adding features.',
519
+ ],
520
+ git: [
521
+ 'Establish commit conventions now while the team is small.',
522
+ ],
523
+ },
524
+ established: {
525
+ code_quality: [
526
+ 'Match existing code patterns exactly. Read 3-5 similar files before generating new ones.',
527
+ 'Do not introduce new patterns without discussing with the team first.',
528
+ 'Prefer incremental improvements over rewrites.',
529
+ ],
530
+ testing: [
531
+ 'Maintain existing test patterns. Do not switch test frameworks mid-project.',
532
+ 'Add tests for any code you touch, even if existing code lacked them.',
533
+ ],
534
+ git: [
535
+ 'Follow the existing commit message conventions visible in git log.',
536
+ ],
537
+ },
538
+ mature: {
539
+ code_quality: [
540
+ 'Match existing code patterns exactly. Read 3-5 similar files before generating new ones.',
541
+ 'Do not introduce new patterns without discussing with the team first.',
542
+ 'Prefer incremental improvements over rewrites.',
543
+ 'Consider backward compatibility for any public API changes.',
544
+ ],
545
+ testing: [
546
+ 'Maintain existing test patterns. Do not switch test frameworks mid-project.',
547
+ 'Add tests for any code you touch, even if existing code lacked them.',
548
+ 'Run the full test suite before submitting — regressions in mature codebases are costly.',
549
+ ],
550
+ git: [
551
+ 'Follow the existing commit message conventions visible in git log.',
552
+ 'Keep PRs small and focused — large changes in mature codebases are risky.',
553
+ ],
554
+ },
555
+ };
556
+
557
+ // ── Tooling Rules Builder ──
558
+
559
+ function buildToolingRules(profile) {
560
+ const rules = [];
561
+ if (profile.tooling.linter)
562
+ rules.push(`Linter: ${profile.tooling.linter.type} (${profile.tooling.linter.configFile}). Run before committing.`);
563
+ if (profile.tooling.formatter)
564
+ rules.push(`Formatter: ${profile.tooling.formatter.type} (${profile.tooling.formatter.configFile}). Run before committing.`);
565
+ if (profile.tooling.testFramework)
566
+ rules.push(`Test framework: ${profile.tooling.testFramework.type}. Do not introduce a second test runner.`);
567
+ if (profile.commands.test)
568
+ rules.push(`Test command: \`${profile.commands.test}\``);
569
+ if (profile.commands.lint)
570
+ rules.push(`Lint command: \`${profile.commands.lint}\``);
571
+ if (profile.commands.build)
572
+ rules.push(`Build command: \`${profile.commands.build}\``);
573
+ if (profile.commands.dev)
574
+ rules.push(`Dev server: \`${profile.commands.dev}\``);
575
+ if (profile.commands.typecheck)
576
+ rules.push(`Type check: \`${profile.commands.typecheck}\``);
577
+ if (profile.monorepo.detected)
578
+ rules.push(`Monorepo (${profile.monorepo.type}). Changes may affect multiple packages.`);
579
+ return rules;
580
+ }
581
+
582
+ // ── Cursor Rule Builder (with optional profile) ──
583
+
584
+ export function buildCursorRule(ruleId, profile) {
585
+ const base = CURSOR_RULES[ruleId];
586
+ if (!base) return null;
587
+ if (!profile || ruleId !== 'general') return base;
588
+
589
+ // Inject project context into general.mdc
590
+ const lines = [MATURITY_NOTES[profile.maturity], ...buildToolingRules(profile)];
591
+ return `${base.trimEnd()}\n\n# Project Context\n\n${formatRules(lines)}\n`;
592
+ }
593
+
594
+ // ── Builder Helpers ──
595
+
596
+ const MATURITY_NOTES = {
597
+ greenfield: 'This is a new project — set up conventions and infrastructure early.',
598
+ early: 'This is an early-stage project — establish patterns before the codebase grows.',
599
+ established: 'This is an established codebase — match existing patterns exactly.',
600
+ mature: 'This is a mature codebase — match existing patterns, prefer incremental changes over rewrites.',
601
+ };
602
+
603
+ function formatRules(rules) {
604
+ return rules.map((r) => `- ${r}`).join('\n');
605
+ }
606
+
607
+ // The profile-derived fragments shared by CLAUDE.md and GEMINI.md: a maturity
608
+ // line appended to the Behavior section, and an optional commands/tooling section.
609
+ function profileSections(profile) {
610
+ if (!profile) return { behaviorNote: '', commandsSection: '' };
611
+ const toolingRules = buildToolingRules(profile);
612
+ return {
613
+ behaviorNote: `\n- ${MATURITY_NOTES[profile.maturity]}`,
614
+ commandsSection: toolingRules.length > 0
615
+ ? `\n## Project Commands & Tooling\n\n${formatRules(toolingRules)}\n`
616
+ : '',
617
+ };
618
+ }
619
+
620
+ function getStackNames(selectedStacks) {
621
+ return selectedStacks
622
+ .map((id) => TECH_STACKS.find((s) => s.id === id)?.label || id)
623
+ .join(', ');
624
+ }
625
+
626
+ function composeStackRules(selectedStacks) {
627
+ const sections = [];
628
+ for (const stackId of selectedStacks) {
629
+ const stack = AGENT_RULES.stacks[stackId];
630
+ const meta = TECH_STACKS.find((s) => s.id === stackId);
631
+ if (!stack || !meta) continue;
632
+
633
+ let section = `## ${meta.name} Rules\n\n${formatRules(stack.rules)}`;
634
+ if (stack.anti_patterns.length > 0) {
635
+ section += `\n\n### DO NOT\n\n${formatRules(stack.anti_patterns)}`;
636
+ }
637
+ sections.push(section);
638
+ }
639
+ return sections.join('\n\n');
640
+ }
641
+
642
+ // ── Builder Functions ──
643
+
644
+ export function buildAgentsMd(selectedStacks, profile = null) {
645
+ const u = AGENT_RULES.universal;
646
+ const stackNames = getStackNames(selectedStacks);
647
+ const stackRules = composeStackRules(selectedStacks);
648
+
649
+ const ctx = CONTEXTUAL_RULES[profile?.maturity];
650
+
651
+ const codeQuality = [...u.code_quality];
652
+ if (ctx?.code_quality) codeQuality.push(...ctx.code_quality);
653
+
654
+ const testing = [...u.testing];
655
+ if (ctx?.testing) testing.push(...ctx.testing);
656
+
657
+ const git = [...u.git];
658
+ if (ctx?.git) git.push(...ctx.git);
659
+
660
+ let projectContext = '<!-- Describe your project specifics below: architecture, key commands, env vars -->';
661
+ if (profile) {
662
+ const lines = [];
663
+ const maturityLabel = `${profile.maturity} (${profile.git.commitCount} commits, ${profile.git.ageInDays} days)`;
664
+ lines.push(`- **Maturity**: ${maturityLabel}`);
665
+ if (profile.tooling.packageManager)
666
+ lines.push(`- **Package manager**: ${profile.tooling.packageManager}`);
667
+ const toolingRules = buildToolingRules(profile);
668
+ for (const rule of toolingRules) {
669
+ lines.push(`- ${rule}`);
670
+ }
671
+ projectContext = lines.join('\n');
672
+ }
673
+
674
+ return `# AGENTS.md — Rules for AI Agents
675
+
676
+ > Every AI agent working in this repo MUST follow these rules.
677
+
678
+ ## Tech Stack
679
+
680
+ ${stackNames}
681
+
682
+ ## Code Quality
683
+
684
+ ${formatRules(codeQuality)}
685
+
686
+ ## Error Handling
687
+
688
+ ${formatRules(u.error_handling)}
689
+
690
+ ## Anti-Patterns — DO NOT
691
+
692
+ ${formatRules(u.anti_patterns)}
693
+
694
+ ## Testing
695
+
696
+ ${formatRules(testing)}
697
+
698
+ ## Git
699
+
700
+ ${formatRules(git)}
701
+
702
+ ${stackRules}
703
+
704
+ ## Project Context
705
+
706
+ ${projectContext}
707
+ `;
708
+ }
709
+
710
+ // Claude Code does not read AGENTS.md; its documented pattern is a CLAUDE.md
711
+ // that imports it with `@AGENTS.md` so the two never drift. The import is only
712
+ // emitted when dxai is also writing AGENTS.md.
713
+ export function buildClaudeMd(selectedStacks, profile = null, { importAgentsMd = false } = {}) {
714
+ const stackNames = getStackNames(selectedStacks);
715
+ const stackRules = composeStackRules(selectedStacks);
716
+
717
+ const { behaviorNote, commandsSection } = profileSections(profile);
718
+ const agentsImport = importAgentsMd
719
+ ? '@AGENTS.md\n\n<!-- Shared project context lives in AGENTS.md (imported above). Keep Claude-specific guidance below. -->\n\n'
720
+ : '';
721
+
722
+ return `# CLAUDE.md — Instructions for Claude Code
723
+
724
+ ${agentsImport}## Behavior
725
+
726
+ - Read the full file before editing. Do not assume structure from names.
727
+ - To fix a bug: find the failing test first. No test? Write one that reproduces it before fixing.
728
+ - After every change, run the relevant tests. Not done until tests pass.
729
+ - For multi-file changes, use extended thinking. List all files you'll touch first.
730
+ - Check for existing patterns before generating new files. Look at 2-3 similar files.${behaviorNote}
731
+
732
+ ## MCP Tools
733
+
734
+ - Use \`context7\` to look up API docs before using any library. Do not guess from memory.
735
+ - Use GitHub MCP for issue/PR operations.
736
+ - Use browser MCP to verify UI changes visually.
737
+
738
+ ## Tech Stack
739
+
740
+ ${stackNames}
741
+
742
+ ## Stack Rules
743
+
744
+ ${stackRules}${commandsSection}`;
745
+ }
746
+
747
+ export function buildGeminiMd(selectedStacks, profile = null) {
748
+ const stackNames = getStackNames(selectedStacks);
749
+ const stackRules = composeStackRules(selectedStacks);
750
+
751
+ const { behaviorNote, commandsSection } = profileSections(profile);
752
+
753
+ return `# GEMINI.md — Instructions for Gemini
754
+
755
+ ## Behavior
756
+
757
+ - Plan before coding. For multi-file changes, outline all affected files first.
758
+ - Match existing code style exactly. Check adjacent files before writing new code.
759
+ - Do not invent APIs that don't exist in the codebase. Verify first.
760
+ - Run tests after changes.${behaviorNote}
761
+
762
+ ## Tech Stack
763
+
764
+ ${stackNames}
765
+
766
+ ## Stack Rules
767
+
768
+ ${stackRules}${commandsSection}`;
769
+ }