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.
- package/LICENSE +21 -0
- package/README.md +172 -0
- package/bin/cli.js +272 -0
- package/package.json +64 -0
- package/src/auto-update.js +106 -0
- package/src/branding.js +80 -0
- package/src/cleanup.js +615 -0
- package/src/config-remover.js +325 -0
- package/src/config-writer.js +781 -0
- package/src/detect-project.js +316 -0
- package/src/detect.js +587 -0
- package/src/fs-atomic.js +35 -0
- package/src/handshake.js +123 -0
- package/src/index.js +966 -0
- package/src/inspect.js +283 -0
- package/src/manifest.js +179 -0
- package/src/mcp-cmd.js +282 -0
- package/src/net.js +72 -0
- package/src/profile.js +139 -0
- package/src/registry/automation-tools.js +6 -0
- package/src/registry/data/automation-tools.json +37 -0
- package/src/registry/data/mcp-servers.json +451 -0
- package/src/registry/data/skills.json +132 -0
- package/src/registry/loader.js +102 -0
- package/src/registry/mcp-registry.js +292 -0
- package/src/registry/mcp-servers.js +72 -0
- package/src/registry/skills.js +10 -0
- package/src/registry/stacks.js +769 -0
- package/src/registry/validate.js +209 -0
- package/src/rollback.js +182 -0
- package/src/runtime.js +40 -0
- package/src/select.js +72 -0
- package/src/update.js +126 -0
|
@@ -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
|
+
}
|