@malamute/ai-rules 1.0.0 → 1.3.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/README.md +272 -121
- package/bin/cli.js +5 -2
- package/configs/_shared/CLAUDE.md +52 -149
- package/configs/_shared/rules/conventions/documentation.md +324 -0
- package/configs/_shared/rules/conventions/git.md +265 -0
- package/configs/_shared/rules/conventions/npm.md +80 -0
- package/configs/_shared/{.claude/rules → rules/conventions}/performance.md +1 -1
- package/configs/_shared/rules/conventions/principles.md +334 -0
- package/configs/_shared/rules/devops/ci-cd.md +262 -0
- package/configs/_shared/rules/devops/docker.md +275 -0
- package/configs/_shared/rules/devops/nx.md +194 -0
- package/configs/_shared/rules/domain/backend/api-design.md +203 -0
- package/configs/_shared/rules/lang/csharp/async.md +220 -0
- package/configs/_shared/rules/lang/csharp/csharp.md +314 -0
- package/configs/_shared/rules/lang/csharp/linq.md +210 -0
- package/configs/_shared/rules/lang/python/async.md +337 -0
- package/configs/_shared/rules/lang/python/celery.md +476 -0
- package/configs/_shared/rules/lang/python/config.md +339 -0
- package/configs/{python/.claude/rules → _shared/rules/lang/python}/database/sqlalchemy.md +6 -1
- package/configs/_shared/rules/lang/python/deployment.md +523 -0
- package/configs/_shared/rules/lang/python/error-handling.md +330 -0
- package/configs/_shared/rules/lang/python/migrations.md +421 -0
- package/configs/_shared/rules/lang/python/python.md +172 -0
- package/configs/_shared/rules/lang/python/repository.md +383 -0
- package/configs/{python/.claude/rules → _shared/rules/lang/python}/testing.md +2 -69
- package/configs/_shared/rules/lang/typescript/async.md +447 -0
- package/configs/_shared/rules/lang/typescript/generics.md +356 -0
- package/configs/_shared/rules/lang/typescript/typescript.md +212 -0
- package/configs/_shared/rules/quality/error-handling.md +48 -0
- package/configs/_shared/rules/quality/logging.md +45 -0
- package/configs/_shared/rules/quality/observability.md +240 -0
- package/configs/_shared/rules/quality/testing-patterns.md +65 -0
- package/configs/_shared/rules/security/secrets-management.md +222 -0
- package/configs/_shared/skills/analysis/explore/SKILL.md +257 -0
- package/configs/_shared/skills/analysis/security-audit/SKILL.md +184 -0
- package/configs/_shared/skills/dev/api-endpoint/SKILL.md +126 -0
- package/configs/_shared/{.claude/commands/generate-tests.md → skills/dev/generate-tests/SKILL.md} +6 -0
- package/configs/_shared/{.claude/commands/fix-issue.md → skills/git/fix-issue/SKILL.md} +6 -0
- package/configs/_shared/{.claude/commands/review-pr.md → skills/git/review-pr/SKILL.md} +6 -0
- package/configs/_shared/skills/infra/deploy/SKILL.md +139 -0
- package/configs/_shared/skills/infra/docker/SKILL.md +95 -0
- package/configs/_shared/skills/infra/migration/SKILL.md +158 -0
- package/configs/_shared/skills/nx/nx-affected/SKILL.md +72 -0
- package/configs/_shared/skills/nx/nx-lib/SKILL.md +375 -0
- package/configs/angular/CLAUDE.md +24 -216
- package/configs/angular/{.claude/rules → rules/core}/components.md +69 -15
- package/configs/angular/rules/core/resource.md +285 -0
- package/configs/angular/rules/core/signals.md +323 -0
- package/configs/angular/rules/http.md +338 -0
- package/configs/angular/rules/routing.md +291 -0
- package/configs/angular/rules/ssr.md +312 -0
- package/configs/angular/rules/state/signal-store.md +408 -0
- package/configs/angular/{.claude/rules → rules/state}/state.md +2 -2
- package/configs/angular/{.claude/rules → rules}/testing.md +7 -7
- package/configs/angular/rules/ui/aria.md +422 -0
- package/configs/angular/rules/ui/forms.md +424 -0
- package/configs/angular/rules/ui/pipes-directives.md +335 -0
- package/configs/angular/{.claude/settings.json → settings.json} +3 -0
- package/configs/dotnet/CLAUDE.md +53 -286
- package/configs/dotnet/rules/background-services.md +552 -0
- package/configs/dotnet/rules/configuration.md +426 -0
- package/configs/dotnet/rules/ddd.md +447 -0
- package/configs/dotnet/rules/dependency-injection.md +343 -0
- package/configs/dotnet/rules/mediatr.md +320 -0
- package/configs/dotnet/rules/middleware.md +489 -0
- package/configs/dotnet/rules/result-pattern.md +363 -0
- package/configs/dotnet/rules/validation.md +388 -0
- package/configs/dotnet/settings.json +29 -0
- package/configs/fastapi/CLAUDE.md +144 -0
- package/configs/fastapi/rules/background-tasks.md +254 -0
- package/configs/fastapi/rules/dependencies.md +170 -0
- package/configs/{python/.claude → fastapi}/rules/fastapi.md +61 -1
- package/configs/fastapi/rules/lifespan.md +274 -0
- package/configs/fastapi/rules/middleware.md +229 -0
- package/configs/fastapi/rules/pydantic.md +433 -0
- package/configs/fastapi/rules/responses.md +251 -0
- package/configs/fastapi/rules/routers.md +202 -0
- package/configs/fastapi/rules/security.md +222 -0
- package/configs/fastapi/rules/testing.md +251 -0
- package/configs/fastapi/rules/websockets.md +298 -0
- package/configs/fastapi/settings.json +35 -0
- package/configs/flask/CLAUDE.md +166 -0
- package/configs/flask/rules/blueprints.md +208 -0
- package/configs/flask/rules/cli.md +285 -0
- package/configs/flask/rules/configuration.md +281 -0
- package/configs/flask/rules/context.md +238 -0
- package/configs/flask/rules/error-handlers.md +278 -0
- package/configs/flask/rules/extensions.md +278 -0
- package/configs/flask/rules/flask.md +171 -0
- package/configs/flask/rules/marshmallow.md +206 -0
- package/configs/flask/rules/security.md +267 -0
- package/configs/flask/rules/testing.md +284 -0
- package/configs/flask/settings.json +35 -0
- package/configs/nestjs/CLAUDE.md +57 -215
- package/configs/nestjs/rules/common-patterns.md +300 -0
- package/configs/nestjs/rules/filters.md +376 -0
- package/configs/nestjs/rules/interceptors.md +317 -0
- package/configs/nestjs/rules/middleware.md +321 -0
- package/configs/nestjs/{.claude/rules → rules}/modules.md +26 -0
- package/configs/nestjs/rules/pipes.md +351 -0
- package/configs/nestjs/rules/websockets.md +451 -0
- package/configs/nestjs/settings.json +31 -0
- package/configs/nextjs/CLAUDE.md +69 -331
- package/configs/nextjs/rules/api-routes.md +358 -0
- package/configs/nextjs/rules/authentication.md +355 -0
- package/configs/nextjs/{.claude/rules → rules}/components.md +52 -0
- package/configs/nextjs/rules/data-fetching.md +249 -0
- package/configs/nextjs/rules/database.md +400 -0
- package/configs/nextjs/rules/middleware.md +303 -0
- package/configs/nextjs/rules/routing.md +324 -0
- package/configs/nextjs/rules/seo.md +350 -0
- package/configs/nextjs/rules/server-actions.md +353 -0
- package/configs/nextjs/{.claude/rules → rules}/state/zustand.md +6 -6
- package/configs/nextjs/{.claude/settings.json → settings.json} +7 -0
- package/package.json +24 -9
- package/src/cli.js +218 -0
- package/src/config.js +63 -0
- package/src/index.js +4 -0
- package/src/installer.js +414 -0
- package/src/merge.js +109 -0
- package/src/tech-config.json +45 -0
- package/src/utils.js +88 -0
- package/configs/dotnet/.claude/settings.json +0 -9
- package/configs/nestjs/.claude/settings.json +0 -15
- package/configs/python/.claude/rules/flask.md +0 -332
- package/configs/python/.claude/settings.json +0 -18
- package/configs/python/CLAUDE.md +0 -273
- package/src/install.js +0 -315
- /package/configs/_shared/{.claude/rules → rules/domain/frontend}/accessibility.md +0 -0
- /package/configs/_shared/{.claude/rules → rules/security}/security.md +0 -0
- /package/configs/_shared/{.claude/skills → skills/dev}/debug/SKILL.md +0 -0
- /package/configs/_shared/{.claude/skills → skills/dev}/learning/SKILL.md +0 -0
- /package/configs/_shared/{.claude/skills → skills/dev}/spec/SKILL.md +0 -0
- /package/configs/_shared/{.claude/skills → skills/git}/review/SKILL.md +0 -0
- /package/configs/dotnet/{.claude/rules → rules}/api.md +0 -0
- /package/configs/dotnet/{.claude/rules → rules}/architecture.md +0 -0
- /package/configs/dotnet/{.claude/rules → rules}/database/efcore.md +0 -0
- /package/configs/dotnet/{.claude/rules → rules}/testing.md +0 -0
- /package/configs/nestjs/{.claude/rules → rules}/auth.md +0 -0
- /package/configs/nestjs/{.claude/rules → rules}/database/prisma.md +0 -0
- /package/configs/nestjs/{.claude/rules → rules}/database/typeorm.md +0 -0
- /package/configs/nestjs/{.claude/rules → rules}/testing.md +0 -0
- /package/configs/nestjs/{.claude/rules → rules}/validation.md +0 -0
- /package/configs/nextjs/{.claude/rules → rules}/state/redux-toolkit.md +0 -0
- /package/configs/nextjs/{.claude/rules → rules}/testing.md +0 -0
|
@@ -82,7 +82,7 @@ export const useUserStore = create<UserState>((set) => ({
|
|
|
82
82
|
|
|
83
83
|
```typescript
|
|
84
84
|
// stores/app-store.ts
|
|
85
|
-
import { create } from 'zustand';
|
|
85
|
+
import { create, StateCreator } from 'zustand';
|
|
86
86
|
|
|
87
87
|
// User slice
|
|
88
88
|
interface UserSlice {
|
|
@@ -90,7 +90,7 @@ interface UserSlice {
|
|
|
90
90
|
setUser: (user: User | null) => void;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
const createUserSlice = (set
|
|
93
|
+
const createUserSlice: StateCreator<AppStore, [], [], UserSlice> = (set) => ({
|
|
94
94
|
user: null,
|
|
95
95
|
setUser: (user) => set({ user }),
|
|
96
96
|
});
|
|
@@ -103,13 +103,13 @@ interface CartSlice {
|
|
|
103
103
|
clearCart: () => void;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
const createCartSlice = (set
|
|
106
|
+
const createCartSlice: StateCreator<AppStore, [], [], CartSlice> = (set) => ({
|
|
107
107
|
items: [],
|
|
108
|
-
addItem: (item) => set((state
|
|
108
|
+
addItem: (item) => set((state) => ({
|
|
109
109
|
items: [...state.items, item]
|
|
110
110
|
})),
|
|
111
|
-
removeItem: (id) => set((state
|
|
112
|
-
items: state.items.filter((item
|
|
111
|
+
removeItem: (id) => set((state) => ({
|
|
112
|
+
items: state.items.filter((item) => item.id !== id)
|
|
113
113
|
})),
|
|
114
114
|
clearCart: () => set({ items: [] }),
|
|
115
115
|
});
|
|
@@ -14,16 +14,23 @@
|
|
|
14
14
|
"Bash(npm install *)",
|
|
15
15
|
"Bash(npm ci)",
|
|
16
16
|
"Bash(npx nx *)",
|
|
17
|
+
"Bash(npx prisma *)",
|
|
17
18
|
"Read",
|
|
18
19
|
"Edit",
|
|
19
20
|
"Write"
|
|
20
21
|
],
|
|
21
22
|
"deny": [
|
|
23
|
+
"Bash(git push *)",
|
|
24
|
+
"Bash(git push)",
|
|
22
25
|
"Bash(rm -rf *)",
|
|
23
26
|
"Bash(nx reset)",
|
|
24
27
|
"Read(.env)",
|
|
25
28
|
"Read(.env.*)",
|
|
26
29
|
"Read(**/secrets/**)"
|
|
27
30
|
]
|
|
31
|
+
},
|
|
32
|
+
"env": {
|
|
33
|
+
"NODE_ENV": "development",
|
|
34
|
+
"NX_DAEMON": "true"
|
|
28
35
|
}
|
|
29
36
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malamute/ai-rules",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Claude Code configuration boilerplates for Angular, Next.js, NestJS, .NET, Python and more",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
},
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"bin": "./bin/cli.js",
|
|
9
8
|
"scripts": {
|
|
10
|
-
"test": "
|
|
9
|
+
"test": "vitest run",
|
|
10
|
+
"test:watch": "vitest",
|
|
11
|
+
"test:coverage": "vitest run --coverage",
|
|
12
|
+
"lint": "eslint src bin",
|
|
13
|
+
"lint:rules": "node scripts/lint-rules.js",
|
|
14
|
+
"validate": "npm test && npm run lint:rules"
|
|
11
15
|
},
|
|
12
16
|
"keywords": [
|
|
13
17
|
"claude",
|
|
@@ -24,12 +28,16 @@
|
|
|
24
28
|
"python",
|
|
25
29
|
"fastapi"
|
|
26
30
|
],
|
|
27
|
-
"author": "",
|
|
31
|
+
"author": "Mehdi Chaabi",
|
|
28
32
|
"license": "MIT",
|
|
29
33
|
"repository": {
|
|
30
34
|
"type": "git",
|
|
31
|
-
"url": ""
|
|
35
|
+
"url": "git+https://github.com/SpaceMalamute/ai-rules.git"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/SpaceMalamute/ai-rules/issues"
|
|
32
39
|
},
|
|
40
|
+
"homepage": "https://github.com/SpaceMalamute/ai-rules#readme",
|
|
33
41
|
"files": [
|
|
34
42
|
"bin",
|
|
35
43
|
"src",
|
|
@@ -37,5 +45,12 @@
|
|
|
37
45
|
],
|
|
38
46
|
"engines": {
|
|
39
47
|
"node": ">=18.0.0"
|
|
40
|
-
}
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@eslint/js": "^9.39.2",
|
|
51
|
+
"eslint": "^9.39.2",
|
|
52
|
+
"husky": "^9.1.7",
|
|
53
|
+
"vitest": "^2.0.0"
|
|
54
|
+
},
|
|
55
|
+
"packageManager": "yarn@4.12.0"
|
|
41
56
|
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import readline from 'readline';
|
|
2
|
+
import { colors, log } from './utils.js';
|
|
3
|
+
import { VERSION, AVAILABLE_TECHS } from './config.js';
|
|
4
|
+
import { init, update, status, listTechnologies } from './installer.js';
|
|
5
|
+
|
|
6
|
+
function printUsage() {
|
|
7
|
+
console.log(`
|
|
8
|
+
${colors.bold('AI Rules')} v${VERSION} - Claude Code configuration boilerplates
|
|
9
|
+
|
|
10
|
+
${colors.bold('Usage:')}
|
|
11
|
+
ai-rules init [tech] [tech2] [options]
|
|
12
|
+
ai-rules update [options]
|
|
13
|
+
ai-rules status
|
|
14
|
+
ai-rules list
|
|
15
|
+
|
|
16
|
+
${colors.bold('Commands:')}
|
|
17
|
+
init Install configuration (interactive if no tech specified)
|
|
18
|
+
update Update installed configs to latest version
|
|
19
|
+
status Show current installation status
|
|
20
|
+
list List available technologies
|
|
21
|
+
|
|
22
|
+
${colors.bold('Technologies:')}
|
|
23
|
+
angular Angular 21 + Nx + NgRx
|
|
24
|
+
nextjs Next.js 15 + React 19
|
|
25
|
+
nestjs NestJS + Prisma/TypeORM
|
|
26
|
+
dotnet .NET 9 + EF Core
|
|
27
|
+
fastapi FastAPI + SQLAlchemy + Pydantic
|
|
28
|
+
flask Flask + SQLAlchemy + Marshmallow
|
|
29
|
+
|
|
30
|
+
${colors.bold('Options:')}
|
|
31
|
+
--minimal Only install CLAUDE.md, settings.json, and tech rules (no shared skills/rules)
|
|
32
|
+
--target <dir> Target directory (default: current directory)
|
|
33
|
+
--dry-run Preview changes without writing files
|
|
34
|
+
--force Overwrite files without backup (update command)
|
|
35
|
+
|
|
36
|
+
${colors.bold('Examples:')}
|
|
37
|
+
ai-rules init # Interactive mode
|
|
38
|
+
ai-rules init angular # Full install (skills + rules)
|
|
39
|
+
ai-rules init angular --minimal # Minimal install
|
|
40
|
+
ai-rules init nextjs --dry-run
|
|
41
|
+
ai-rules update
|
|
42
|
+
ai-rules update --force
|
|
43
|
+
ai-rules status
|
|
44
|
+
`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function prompt(question) {
|
|
48
|
+
const rl = readline.createInterface({
|
|
49
|
+
input: process.stdin,
|
|
50
|
+
output: process.stdout,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
rl.question(question, (answer) => {
|
|
55
|
+
rl.close();
|
|
56
|
+
resolve(answer.trim());
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function multiSelect(message, choices) {
|
|
62
|
+
console.log(`\n${colors.bold(message)}`);
|
|
63
|
+
console.log(colors.dim('(enter numbers separated by spaces, or "all")'));
|
|
64
|
+
console.log('');
|
|
65
|
+
|
|
66
|
+
choices.forEach((choice, i) => {
|
|
67
|
+
console.log(` ${colors.cyan(i + 1)}. ${choice.name} ${colors.dim(`- ${choice.description}`)}`);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
console.log('');
|
|
71
|
+
const answer = await prompt('Your selection: ');
|
|
72
|
+
|
|
73
|
+
if (answer.toLowerCase() === 'all') {
|
|
74
|
+
return choices.map((c) => c.value);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const indices = answer
|
|
78
|
+
.split(/[\s,]+/)
|
|
79
|
+
.map((s) => parseInt(s, 10) - 1)
|
|
80
|
+
.filter((i) => i >= 0 && i < choices.length);
|
|
81
|
+
|
|
82
|
+
return indices.map((i) => choices[i].value);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function interactiveInit() {
|
|
86
|
+
console.log(`\n${colors.bold('AI Rules')} - Interactive Setup\n`);
|
|
87
|
+
|
|
88
|
+
const techChoices = [
|
|
89
|
+
{ name: 'Angular', value: 'angular', description: 'Angular 21 + Nx + NgRx + Signals' },
|
|
90
|
+
{ name: 'Next.js', value: 'nextjs', description: 'Next.js 15 + React 19 + App Router' },
|
|
91
|
+
{ name: 'NestJS', value: 'nestjs', description: 'NestJS 11 + Prisma/TypeORM + Passport' },
|
|
92
|
+
{ name: '.NET', value: 'dotnet', description: '.NET 9 + ASP.NET Core + EF Core' },
|
|
93
|
+
{ name: 'FastAPI', value: 'fastapi', description: 'FastAPI + SQLAlchemy 2.0 + Pydantic v2' },
|
|
94
|
+
{ name: 'Flask', value: 'flask', description: 'Flask + SQLAlchemy 2.0 + Marshmallow' },
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
const techs = await multiSelect('Select technologies:', techChoices);
|
|
98
|
+
|
|
99
|
+
if (techs.length === 0) {
|
|
100
|
+
log.error('No technology selected');
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const extraChoices = [
|
|
105
|
+
{ name: 'Skills', value: 'skills', description: '/learning, /review, /spec, /debug, etc.' },
|
|
106
|
+
{ name: 'Shared Rules', value: 'rules', description: 'security, performance, accessibility' },
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
const extras = await multiSelect('Include extras:', extraChoices);
|
|
110
|
+
|
|
111
|
+
const targetDir = await prompt(`Target directory ${colors.dim('(. for current)')}: `) || '.';
|
|
112
|
+
|
|
113
|
+
const options = {
|
|
114
|
+
target: targetDir === '.' ? null : targetDir,
|
|
115
|
+
withSkills: extras.includes('skills'),
|
|
116
|
+
withRules: extras.includes('rules'),
|
|
117
|
+
all: false,
|
|
118
|
+
dryRun: false,
|
|
119
|
+
force: false,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
console.log('');
|
|
123
|
+
return { techs, options };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export async function run(args) {
|
|
127
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
128
|
+
printUsage();
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (args.length === 0) {
|
|
133
|
+
printUsage();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const command = args[0];
|
|
138
|
+
|
|
139
|
+
if (command === 'list') {
|
|
140
|
+
listTechnologies();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (command === 'status') {
|
|
145
|
+
const targetIndex = args.indexOf('--target');
|
|
146
|
+
const targetDir = targetIndex !== -1 ? args[targetIndex + 1] : process.cwd();
|
|
147
|
+
status(targetDir);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (command === 'update') {
|
|
152
|
+
const options = {
|
|
153
|
+
target: null,
|
|
154
|
+
dryRun: args.includes('--dry-run'),
|
|
155
|
+
force: args.includes('--force'),
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const targetIndex = args.indexOf('--target');
|
|
159
|
+
if (targetIndex !== -1) {
|
|
160
|
+
options.target = args[targetIndex + 1];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
await update(options);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (command === 'init') {
|
|
168
|
+
const minimal = args.includes('--minimal');
|
|
169
|
+
const options = {
|
|
170
|
+
target: null,
|
|
171
|
+
withSkills: !minimal,
|
|
172
|
+
withRules: !minimal,
|
|
173
|
+
dryRun: args.includes('--dry-run'),
|
|
174
|
+
force: args.includes('--force'),
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const techs = [];
|
|
178
|
+
|
|
179
|
+
for (let i = 1; i < args.length; i++) {
|
|
180
|
+
const arg = args[i];
|
|
181
|
+
|
|
182
|
+
if (arg === '--minimal') {
|
|
183
|
+
// Already handled above
|
|
184
|
+
} else if (arg === '--target') {
|
|
185
|
+
options.target = args[++i];
|
|
186
|
+
} else if (arg === '--dry-run' || arg === '--force') {
|
|
187
|
+
// Already handled
|
|
188
|
+
} else if (!arg.startsWith('-')) {
|
|
189
|
+
if (AVAILABLE_TECHS.includes(arg)) {
|
|
190
|
+
techs.push(arg);
|
|
191
|
+
} else {
|
|
192
|
+
log.error(`Unknown technology: ${arg}`);
|
|
193
|
+
console.log(`Available: ${AVAILABLE_TECHS.join(', ')}`);
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Interactive mode if no techs specified
|
|
200
|
+
if (techs.length === 0) {
|
|
201
|
+
try {
|
|
202
|
+
const result = await interactiveInit();
|
|
203
|
+
init(result.techs, { ...options, ...result.options });
|
|
204
|
+
} catch (_e) {
|
|
205
|
+
console.log('\nAborted.');
|
|
206
|
+
process.exit(0);
|
|
207
|
+
}
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
init(techs, options);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
log.error(`Unknown command: ${command}`);
|
|
216
|
+
printUsage();
|
|
217
|
+
process.exit(1);
|
|
218
|
+
}
|
package/src/config.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { createRequire } from 'module';
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
|
|
11
|
+
export const CONFIGS_DIR = path.join(__dirname, '..', 'configs');
|
|
12
|
+
export const AVAILABLE_TECHS = ['angular', 'nextjs', 'nestjs', 'dotnet', 'fastapi', 'flask'];
|
|
13
|
+
export const VERSION = require('../package.json').version;
|
|
14
|
+
|
|
15
|
+
export const TECH_CONFIG = JSON.parse(
|
|
16
|
+
fs.readFileSync(path.join(__dirname, 'tech-config.json'), 'utf8')
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get rule directories to include based on selected technologies.
|
|
21
|
+
* Returns paths relative to the rules directory (e.g., "lang/typescript", "domain/frontend").
|
|
22
|
+
*/
|
|
23
|
+
export function getRulePathsToInclude(techs) {
|
|
24
|
+
const paths = new Set();
|
|
25
|
+
const { ruleMapping, alwaysInclude } = TECH_CONFIG;
|
|
26
|
+
|
|
27
|
+
// Always include common rules
|
|
28
|
+
alwaysInclude.forEach((dir) => paths.add(dir));
|
|
29
|
+
|
|
30
|
+
// Add language and domain-specific rules based on selected techs
|
|
31
|
+
for (const tech of techs) {
|
|
32
|
+
const config = TECH_CONFIG.technologies[tech];
|
|
33
|
+
if (!config) continue;
|
|
34
|
+
|
|
35
|
+
// Add language-specific rules (e.g., "lang/typescript")
|
|
36
|
+
if (config.language && ruleMapping.language[config.language]) {
|
|
37
|
+
paths.add(ruleMapping.language[config.language]);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Add domain-specific rules (e.g., "domain/frontend")
|
|
41
|
+
if (config.type && ruleMapping.type[config.type]) {
|
|
42
|
+
paths.add(ruleMapping.type[config.type]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return paths;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Check if a rule path should be included for the given technologies.
|
|
51
|
+
* @param {string} rulePath - Path relative to rules dir (e.g., "lang/python/async.md")
|
|
52
|
+
* @param {Set<string>} includedPaths - Set of paths to include
|
|
53
|
+
* @returns {boolean}
|
|
54
|
+
*/
|
|
55
|
+
export function shouldIncludeRule(rulePath, includedPaths) {
|
|
56
|
+
// Check if the path starts with any of the included paths
|
|
57
|
+
for (const includedPath of includedPaths) {
|
|
58
|
+
if (rulePath === includedPath || rulePath.startsWith(includedPath + '/')) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
package/src/index.js
ADDED