@malamute/ai-rules 1.3.2 → 1.4.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 +108 -98
- package/configs/_shared/rules/conventions/git.md +2 -0
- package/configs/_shared/rules/lang/python/python.md +4 -6
- package/configs/flask/rules/flask.md +4 -6
- package/configs/flask/rules/marshmallow.md +4 -6
- package/package.json +7 -1
- package/src/cli.js +93 -59
- package/src/installer.js +39 -25
- package/src/tech-config.json +1 -6
package/README.md
CHANGED
|
@@ -10,12 +10,12 @@ AI Rules installs curated configuration boilerplates that teach Claude Code your
|
|
|
10
10
|
|
|
11
11
|
## Why Use This?
|
|
12
12
|
|
|
13
|
-
| Without AI Rules
|
|
14
|
-
|
|
15
|
-
| Claude uses generic patterns
|
|
16
|
-
| You repeat "use signals, not decorators" | Angular 21 patterns are built-in
|
|
17
|
-
| Security issues slip through
|
|
18
|
-
| Inconsistent code style
|
|
13
|
+
| Without AI Rules | With AI Rules |
|
|
14
|
+
| ---------------------------------------- | ---------------------------------------- |
|
|
15
|
+
| Claude uses generic patterns | Claude follows your framework's idioms |
|
|
16
|
+
| You repeat "use signals, not decorators" | Angular 21 patterns are built-in |
|
|
17
|
+
| Security issues slip through | OWASP Top 10 rules catch vulnerabilities |
|
|
18
|
+
| Inconsistent code style | Consistent conventions across the team |
|
|
19
19
|
|
|
20
20
|
## Quick Start
|
|
21
21
|
|
|
@@ -24,7 +24,7 @@ AI Rules installs curated configuration boilerplates that teach Claude Code your
|
|
|
24
24
|
npx @malamute/ai-rules init
|
|
25
25
|
|
|
26
26
|
# Or specify your stack directly
|
|
27
|
-
npx @malamute/ai-rules init angular nestjs
|
|
27
|
+
npx @malamute/ai-rules init angular nestjs
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
That's it. Claude Code now understands your stack.
|
|
@@ -41,19 +41,20 @@ npx @malamute/ai-rules <command>
|
|
|
41
41
|
|
|
42
42
|
## Supported Technologies
|
|
43
43
|
|
|
44
|
-
| Technology
|
|
45
|
-
|
|
46
|
-
| **Angular** | Nx + NgRx + Signals + Vitest
|
|
47
|
-
| **Next.js** | App Router + React 19 + Server Components | 15+
|
|
48
|
-
| **NestJS**
|
|
49
|
-
| **.NET**
|
|
50
|
-
| **FastAPI** | Pydantic v2 + SQLAlchemy 2.0 + pytest
|
|
51
|
-
| **Flask**
|
|
44
|
+
| Technology | Stack | Version |
|
|
45
|
+
| ----------- | ----------------------------------------- | ------- |
|
|
46
|
+
| **Angular** | Nx + NgRx + Signals + Vitest | 21+ |
|
|
47
|
+
| **Next.js** | App Router + React 19 + Server Components | 15+ |
|
|
48
|
+
| **NestJS** | Prisma/TypeORM + Passport + Vitest | 11+ |
|
|
49
|
+
| **.NET** | Clean Architecture + MediatR + EF Core | 9+ |
|
|
50
|
+
| **FastAPI** | Pydantic v2 + SQLAlchemy 2.0 + pytest | 0.115+ |
|
|
51
|
+
| **Flask** | Marshmallow + SQLAlchemy 2.0 + pytest | 3.0+ |
|
|
52
52
|
|
|
53
53
|
## Commands
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
56
|
ai-rules init [tech...] # Install configs (interactive if no tech)
|
|
57
|
+
ai-rules add <tech> # Add technology to existing installation
|
|
57
58
|
ai-rules update # Update to latest rules
|
|
58
59
|
ai-rules status # Show installation info
|
|
59
60
|
ai-rules list # List available technologies
|
|
@@ -61,14 +62,14 @@ ai-rules list # List available technologies
|
|
|
61
62
|
|
|
62
63
|
### Options
|
|
63
64
|
|
|
64
|
-
| Option
|
|
65
|
-
|
|
66
|
-
| `--
|
|
67
|
-
| `--
|
|
68
|
-
| `--
|
|
69
|
-
| `--
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
| Option | Description |
|
|
66
|
+
| ---------------- | --------------------------------------------------------- |
|
|
67
|
+
| `--minimal` | Skip skills and shared rules (only tech rules + settings) |
|
|
68
|
+
| `--dry-run` | Preview changes without writing files |
|
|
69
|
+
| `--target <dir>` | Install to a specific directory |
|
|
70
|
+
| `--force` | Overwrite without creating backups |
|
|
71
|
+
|
|
72
|
+
By default, `init` installs everything (skills + shared rules). Use `--minimal` to skip extras.
|
|
72
73
|
|
|
73
74
|
## What Gets Installed
|
|
74
75
|
|
|
@@ -100,9 +101,11 @@ Context-aware rules that activate based on file paths:
|
|
|
100
101
|
```markdown
|
|
101
102
|
---
|
|
102
103
|
paths:
|
|
103
|
-
-
|
|
104
|
+
- '**/*.component.ts'
|
|
104
105
|
---
|
|
106
|
+
|
|
105
107
|
# Angular Component Rules
|
|
108
|
+
|
|
106
109
|
- Use `ChangeDetectionStrategy.OnPush`
|
|
107
110
|
- Use `input()`, `output()`, not decorators
|
|
108
111
|
- Template in separate `.html` file
|
|
@@ -112,33 +115,33 @@ paths:
|
|
|
112
115
|
|
|
113
116
|
Interactive workflows invoked with `/skill-name`:
|
|
114
117
|
|
|
115
|
-
| Skill
|
|
116
|
-
|
|
117
|
-
| `/learning`
|
|
118
|
-
| `/review`
|
|
119
|
-
| `/debug`
|
|
120
|
-
| `/spec`
|
|
121
|
-
| `/fix-issue`
|
|
122
|
-
| `/generate-tests` | Generate comprehensive tests
|
|
118
|
+
| Skill | Description |
|
|
119
|
+
| ----------------- | ----------------------------------------- |
|
|
120
|
+
| `/learning` | Pedagogical mode — explains before coding |
|
|
121
|
+
| `/review` | Code review with security/perf checklist |
|
|
122
|
+
| `/debug` | Structured debugging workflow |
|
|
123
|
+
| `/spec` | Write technical spec before implementing |
|
|
124
|
+
| `/fix-issue` | Analyze GitHub issue and implement fix |
|
|
125
|
+
| `/generate-tests` | Generate comprehensive tests |
|
|
123
126
|
|
|
124
127
|
<details>
|
|
125
128
|
<summary><strong>See all 13 skills</strong></summary>
|
|
126
129
|
|
|
127
|
-
| Skill
|
|
128
|
-
|
|
129
|
-
| `/learning`
|
|
130
|
-
| `/review`
|
|
131
|
-
| `/spec`
|
|
132
|
-
| `/debug`
|
|
133
|
-
| `/fix-issue`
|
|
134
|
-
| `/review-pr`
|
|
135
|
-
| `/generate-tests` | `/generate-tests src/user.ts` | Generate tests
|
|
136
|
-
| `/api-endpoint`
|
|
137
|
-
| `/migration`
|
|
138
|
-
| `/security-audit` | `/security-audit`
|
|
139
|
-
| `/docker`
|
|
140
|
-
| `/deploy`
|
|
141
|
-
| `/explore`
|
|
130
|
+
| Skill | Usage | Description |
|
|
131
|
+
| ----------------- | ----------------------------- | ------------------------------------- |
|
|
132
|
+
| `/learning` | `/learning nextjs` | Explains concepts before implementing |
|
|
133
|
+
| `/review` | `/review src/users/` | Code review with checklist |
|
|
134
|
+
| `/spec` | `/spec add auth` | Technical specification |
|
|
135
|
+
| `/debug` | `/debug TypeError...` | Systematic debugging |
|
|
136
|
+
| `/fix-issue` | `/fix-issue 123` | Fix GitHub issue |
|
|
137
|
+
| `/review-pr` | `/review-pr 456` | Review pull request |
|
|
138
|
+
| `/generate-tests` | `/generate-tests src/user.ts` | Generate tests |
|
|
139
|
+
| `/api-endpoint` | `/api-endpoint POST /users` | Generate API endpoint |
|
|
140
|
+
| `/migration` | `/migration add users` | Database migration |
|
|
141
|
+
| `/security-audit` | `/security-audit` | Security analysis |
|
|
142
|
+
| `/docker` | `/docker` | Dockerfile generation |
|
|
143
|
+
| `/deploy` | `/deploy` | Deployment config |
|
|
144
|
+
| `/explore` | `/explore` | Repository analysis |
|
|
142
145
|
|
|
143
146
|
</details>
|
|
144
147
|
|
|
@@ -146,15 +149,15 @@ Interactive workflows invoked with `/skill-name`:
|
|
|
146
149
|
|
|
147
150
|
Cross-framework rules included with `--with-rules`:
|
|
148
151
|
|
|
149
|
-
| Rule
|
|
150
|
-
|
|
151
|
-
| **security.md**
|
|
152
|
-
| **performance.md**
|
|
153
|
-
| **accessibility.md**
|
|
154
|
-
| **testing-patterns.md** | AAA pattern, mocking, coverage
|
|
155
|
-
| **error-handling.md**
|
|
156
|
-
| **git.md**
|
|
157
|
-
| **observability.md**
|
|
152
|
+
| Rule | What It Covers |
|
|
153
|
+
| ----------------------- | ------------------------------------------- |
|
|
154
|
+
| **security.md** | OWASP Top 10: injection, XSS, CSRF, secrets |
|
|
155
|
+
| **performance.md** | N+1 queries, caching, lazy loading |
|
|
156
|
+
| **accessibility.md** | WCAG 2.1, semantic HTML, ARIA |
|
|
157
|
+
| **testing-patterns.md** | AAA pattern, mocking, coverage |
|
|
158
|
+
| **error-handling.md** | Error categories, response formats |
|
|
159
|
+
| **git.md** | Conventional commits, branching, PRs |
|
|
160
|
+
| **observability.md** | Logging, metrics, tracing |
|
|
158
161
|
|
|
159
162
|
## Examples
|
|
160
163
|
|
|
@@ -162,10 +165,16 @@ Cross-framework rules included with `--with-rules`:
|
|
|
162
165
|
|
|
163
166
|
```bash
|
|
164
167
|
# Angular frontend + NestJS backend
|
|
165
|
-
ai-rules init angular nestjs
|
|
168
|
+
ai-rules init angular nestjs
|
|
166
169
|
|
|
167
170
|
# Next.js frontend + FastAPI backend
|
|
168
|
-
ai-rules init nextjs fastapi
|
|
171
|
+
ai-rules init nextjs fastapi
|
|
172
|
+
|
|
173
|
+
# Add a technology to existing installation
|
|
174
|
+
ai-rules add nestjs
|
|
175
|
+
|
|
176
|
+
# Minimal install (no skills/shared rules)
|
|
177
|
+
ai-rules init angular --minimal
|
|
169
178
|
```
|
|
170
179
|
|
|
171
180
|
### Preview Before Installing
|
|
@@ -175,6 +184,7 @@ ai-rules init angular --dry-run
|
|
|
175
184
|
```
|
|
176
185
|
|
|
177
186
|
Output:
|
|
187
|
+
|
|
178
188
|
```
|
|
179
189
|
DRY RUN - No files will be modified
|
|
180
190
|
|
|
@@ -207,77 +217,77 @@ ai-rules update
|
|
|
207
217
|
<details>
|
|
208
218
|
<summary><strong>Angular</strong></summary>
|
|
209
219
|
|
|
210
|
-
| Aspect
|
|
211
|
-
|
|
212
|
-
| Components | Standalone, OnPush change detection
|
|
213
|
-
| Signals
|
|
214
|
-
| State
|
|
215
|
-
| Structure
|
|
216
|
-
| Tests
|
|
220
|
+
| Aspect | Convention |
|
|
221
|
+
| ---------- | --------------------------------------------- |
|
|
222
|
+
| Components | Standalone, OnPush change detection |
|
|
223
|
+
| Signals | `input()`, `output()`, `model()` functions |
|
|
224
|
+
| State | NgRx with Entity Adapter + Functional Effects |
|
|
225
|
+
| Structure | Nx monorepo with feature/ui/data-access libs |
|
|
226
|
+
| Tests | Vitest + Marble testing |
|
|
217
227
|
|
|
218
228
|
</details>
|
|
219
229
|
|
|
220
230
|
<details>
|
|
221
231
|
<summary><strong>Next.js</strong></summary>
|
|
222
232
|
|
|
223
|
-
| Aspect
|
|
224
|
-
|
|
225
|
-
| Components | Server Components by default
|
|
226
|
-
| Client
|
|
227
|
-
| Data
|
|
228
|
-
| State
|
|
229
|
-
| Structure
|
|
233
|
+
| Aspect | Convention |
|
|
234
|
+
| ---------- | ------------------------------------------ |
|
|
235
|
+
| Components | Server Components by default |
|
|
236
|
+
| Client | `'use client'` directive for interactivity |
|
|
237
|
+
| Data | Server Components + fetch, Server Actions |
|
|
238
|
+
| State | Zustand (simple) / Redux Toolkit (complex) |
|
|
239
|
+
| Structure | App Router with route groups |
|
|
230
240
|
|
|
231
241
|
</details>
|
|
232
242
|
|
|
233
243
|
<details>
|
|
234
244
|
<summary><strong>NestJS</strong></summary>
|
|
235
245
|
|
|
236
|
-
| Aspect
|
|
237
|
-
|
|
238
|
-
| Architecture | Modular Monolith
|
|
239
|
-
| Validation
|
|
240
|
-
| Database
|
|
241
|
-
| Auth
|
|
242
|
-
| Tests
|
|
246
|
+
| Aspect | Convention |
|
|
247
|
+
| ------------ | -------------------------------------- |
|
|
248
|
+
| Architecture | Modular Monolith |
|
|
249
|
+
| Validation | class-validator + class-transformer |
|
|
250
|
+
| Database | Prisma (modern) / TypeORM (decorators) |
|
|
251
|
+
| Auth | Passport + JWT |
|
|
252
|
+
| Tests | Vitest + Supertest |
|
|
243
253
|
|
|
244
254
|
</details>
|
|
245
255
|
|
|
246
256
|
<details>
|
|
247
257
|
<summary><strong>.NET</strong></summary>
|
|
248
258
|
|
|
249
|
-
| Aspect
|
|
250
|
-
|
|
259
|
+
| Aspect | Convention |
|
|
260
|
+
| ------------ | ----------------------------------------- |
|
|
251
261
|
| Architecture | Clean Architecture (Domain → App → Infra) |
|
|
252
|
-
| API
|
|
253
|
-
| CQRS
|
|
254
|
-
| ORM
|
|
255
|
-
| Tests
|
|
262
|
+
| API | Minimal APIs (preferred) or Controllers |
|
|
263
|
+
| CQRS | MediatR for Commands/Queries |
|
|
264
|
+
| ORM | Entity Framework Core |
|
|
265
|
+
| Tests | xUnit + NSubstitute + FluentAssertions |
|
|
256
266
|
|
|
257
267
|
</details>
|
|
258
268
|
|
|
259
269
|
<details>
|
|
260
270
|
<summary><strong>FastAPI</strong></summary>
|
|
261
271
|
|
|
262
|
-
| Aspect
|
|
263
|
-
|
|
264
|
-
| Framework
|
|
265
|
-
| Validation | Pydantic v2
|
|
266
|
-
| ORM
|
|
267
|
-
| Tests
|
|
268
|
-
| Migrations | Alembic
|
|
272
|
+
| Aspect | Convention |
|
|
273
|
+
| ---------- | --------------------------------- |
|
|
274
|
+
| Framework | FastAPI with async/await |
|
|
275
|
+
| Validation | Pydantic v2 |
|
|
276
|
+
| ORM | SQLAlchemy 2.0 with async support |
|
|
277
|
+
| Tests | pytest + httpx |
|
|
278
|
+
| Migrations | Alembic |
|
|
269
279
|
|
|
270
280
|
</details>
|
|
271
281
|
|
|
272
282
|
<details>
|
|
273
283
|
<summary><strong>Flask</strong></summary>
|
|
274
284
|
|
|
275
|
-
| Aspect
|
|
276
|
-
|
|
277
|
-
| Framework
|
|
278
|
-
| Validation | Marshmallow schemas
|
|
279
|
-
| ORM
|
|
280
|
-
| Tests
|
|
285
|
+
| Aspect | Convention |
|
|
286
|
+
| ---------- | --------------------------------------------------- |
|
|
287
|
+
| Framework | Flask 3.0 with Application Factory |
|
|
288
|
+
| Validation | Marshmallow schemas |
|
|
289
|
+
| ORM | SQLAlchemy 2.0 |
|
|
290
|
+
| Tests | pytest |
|
|
281
291
|
| Extensions | Flask-SQLAlchemy, Flask-Migrate, Flask-JWT-Extended |
|
|
282
292
|
|
|
283
293
|
</details>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malamute/ai-rules",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Claude Code configuration boilerplates for Angular, Next.js, NestJS, .NET, Python and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
"test:coverage": "vitest run --coverage",
|
|
12
12
|
"lint": "eslint src bin",
|
|
13
13
|
"lint:rules": "node scripts/lint-rules.js",
|
|
14
|
+
"format": "prettier --write .",
|
|
15
|
+
"format:check": "prettier --check .",
|
|
14
16
|
"validate": "npm test && npm run lint:rules"
|
|
15
17
|
},
|
|
16
18
|
"keywords": [
|
|
@@ -46,10 +48,14 @@
|
|
|
46
48
|
"engines": {
|
|
47
49
|
"node": ">=18.0.0"
|
|
48
50
|
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@inquirer/prompts": "^7.5.3"
|
|
53
|
+
},
|
|
49
54
|
"devDependencies": {
|
|
50
55
|
"@eslint/js": "^9.39.2",
|
|
51
56
|
"eslint": "^9.39.2",
|
|
52
57
|
"husky": "^9.1.7",
|
|
58
|
+
"prettier": "^3.5.3",
|
|
53
59
|
"vitest": "^2.0.0"
|
|
54
60
|
},
|
|
55
61
|
"packageManager": "yarn@4.12.0"
|
package/src/cli.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { checkbox, input } from '@inquirer/prompts';
|
|
2
2
|
import { colors, log } from './utils.js';
|
|
3
3
|
import { VERSION, AVAILABLE_TECHS } from './config.js';
|
|
4
4
|
import { init, update, status, listTechnologies } from './installer.js';
|
|
5
|
+
import { readManifest } from './merge.js';
|
|
5
6
|
|
|
6
7
|
function printUsage() {
|
|
7
8
|
console.log(`
|
|
@@ -9,12 +10,14 @@ ${colors.bold('AI Rules')} v${VERSION} - Claude Code configuration boilerplates
|
|
|
9
10
|
|
|
10
11
|
${colors.bold('Usage:')}
|
|
11
12
|
ai-rules init [tech] [tech2] [options]
|
|
13
|
+
ai-rules add <tech> [options]
|
|
12
14
|
ai-rules update [options]
|
|
13
15
|
ai-rules status
|
|
14
16
|
ai-rules list
|
|
15
17
|
|
|
16
18
|
${colors.bold('Commands:')}
|
|
17
19
|
init Install configuration (interactive if no tech specified)
|
|
20
|
+
add Add a technology to existing installation
|
|
18
21
|
update Update installed configs to latest version
|
|
19
22
|
status Show current installation status
|
|
20
23
|
list List available technologies
|
|
@@ -28,7 +31,7 @@ ${colors.bold('Technologies:')}
|
|
|
28
31
|
flask Flask + SQLAlchemy + Marshmallow
|
|
29
32
|
|
|
30
33
|
${colors.bold('Options:')}
|
|
31
|
-
--minimal Only install
|
|
34
|
+
--minimal Only install settings.json and tech rules (no shared skills/rules)
|
|
32
35
|
--target <dir> Target directory (default: current directory)
|
|
33
36
|
--dry-run Preview changes without writing files
|
|
34
37
|
--force Overwrite files without backup (update command)
|
|
@@ -37,78 +40,54 @@ ${colors.bold('Examples:')}
|
|
|
37
40
|
ai-rules init # Interactive mode
|
|
38
41
|
ai-rules init angular # Full install (skills + rules)
|
|
39
42
|
ai-rules init angular --minimal # Minimal install
|
|
40
|
-
ai-rules
|
|
43
|
+
ai-rules add nestjs # Add NestJS to existing install
|
|
41
44
|
ai-rules update
|
|
42
|
-
ai-rules update --force
|
|
43
45
|
ai-rules status
|
|
44
46
|
`);
|
|
45
47
|
}
|
|
46
48
|
|
|
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
49
|
async function interactiveInit() {
|
|
86
50
|
console.log(`\n${colors.bold('AI Rules')} - Interactive Setup\n`);
|
|
87
51
|
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
52
|
+
const techs = await checkbox({
|
|
53
|
+
message: 'Select technologies:',
|
|
54
|
+
instructions: '(Space to select, Enter to confirm)',
|
|
55
|
+
choices: [
|
|
56
|
+
{ name: 'Angular - Angular 21 + Nx + NgRx + Signals', value: 'angular' },
|
|
57
|
+
{ name: 'Next.js - Next.js 15 + React 19 + App Router', value: 'nextjs' },
|
|
58
|
+
{ name: 'NestJS - NestJS 11 + Prisma/TypeORM + Passport', value: 'nestjs' },
|
|
59
|
+
{ name: '.NET - .NET 9 + ASP.NET Core + EF Core', value: 'dotnet' },
|
|
60
|
+
{ name: 'FastAPI - FastAPI + SQLAlchemy 2.0 + Pydantic v2', value: 'fastapi' },
|
|
61
|
+
{ name: 'Flask - Flask + SQLAlchemy 2.0 + Marshmallow', value: 'flask' },
|
|
62
|
+
],
|
|
63
|
+
});
|
|
98
64
|
|
|
99
65
|
if (techs.length === 0) {
|
|
100
66
|
log.error('No technology selected');
|
|
101
67
|
process.exit(1);
|
|
102
68
|
}
|
|
103
69
|
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
70
|
+
const extras = await checkbox({
|
|
71
|
+
message: 'Include extras:',
|
|
72
|
+
instructions: '(Space to toggle, Enter to confirm)',
|
|
73
|
+
choices: [
|
|
74
|
+
{
|
|
75
|
+
name: 'Skills - /learning, /review, /spec, /debug, etc.',
|
|
76
|
+
value: 'skills',
|
|
77
|
+
checked: true,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'Shared Rules - security, performance, accessibility',
|
|
81
|
+
value: 'rules',
|
|
82
|
+
checked: true,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
});
|
|
110
86
|
|
|
111
|
-
const targetDir = await
|
|
87
|
+
const targetDir = await input({
|
|
88
|
+
message: 'Target directory:',
|
|
89
|
+
default: '.',
|
|
90
|
+
});
|
|
112
91
|
|
|
113
92
|
const options = {
|
|
114
93
|
target: targetDir === '.' ? null : targetDir,
|
|
@@ -164,6 +143,61 @@ export async function run(args) {
|
|
|
164
143
|
return;
|
|
165
144
|
}
|
|
166
145
|
|
|
146
|
+
if (command === 'add') {
|
|
147
|
+
const targetIndex = args.indexOf('--target');
|
|
148
|
+
const targetDir = targetIndex !== -1 ? args[targetIndex + 1] : process.cwd();
|
|
149
|
+
|
|
150
|
+
const manifest = readManifest(targetDir);
|
|
151
|
+
if (!manifest) {
|
|
152
|
+
log.error('No ai-rules installation found.');
|
|
153
|
+
console.log(`Run ${colors.cyan('ai-rules init')} first.`);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const newTechs = [];
|
|
158
|
+
for (let i = 1; i < args.length; i++) {
|
|
159
|
+
const arg = args[i];
|
|
160
|
+
if (arg === '--target') {
|
|
161
|
+
i++; // Skip next arg
|
|
162
|
+
} else if (arg === '--dry-run' || arg === '--force') {
|
|
163
|
+
// Handled below
|
|
164
|
+
} else if (!arg.startsWith('-')) {
|
|
165
|
+
if (AVAILABLE_TECHS.includes(arg)) {
|
|
166
|
+
if (manifest.technologies.includes(arg)) {
|
|
167
|
+
log.warning(`${arg} is already installed, skipping`);
|
|
168
|
+
} else {
|
|
169
|
+
newTechs.push(arg);
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
log.error(`Unknown technology: ${arg}`);
|
|
173
|
+
console.log(`Available: ${AVAILABLE_TECHS.join(', ')}`);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (newTechs.length === 0) {
|
|
180
|
+
log.error('No new technology to add');
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const allTechs = [...manifest.technologies, ...newTechs];
|
|
185
|
+
|
|
186
|
+
const options = {
|
|
187
|
+
target: targetDir === process.cwd() ? null : targetDir,
|
|
188
|
+
withSkills: manifest.options?.withSkills ?? true,
|
|
189
|
+
withRules: manifest.options?.withRules ?? true,
|
|
190
|
+
dryRun: args.includes('--dry-run'),
|
|
191
|
+
force: args.includes('--force'),
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
console.log('');
|
|
195
|
+
log.info(`Adding ${newTechs.join(', ')} to existing installation`);
|
|
196
|
+
|
|
197
|
+
init(allTechs, options);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
167
201
|
if (command === 'init') {
|
|
168
202
|
const minimal = args.includes('--minimal');
|
|
169
203
|
const options = {
|
package/src/installer.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { colors, log, getFilesRecursive, copyDirRecursive, backupFile } from './utils.js';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
CONFIGS_DIR,
|
|
6
|
+
AVAILABLE_TECHS,
|
|
7
|
+
VERSION,
|
|
8
|
+
getRulePathsToInclude,
|
|
9
|
+
shouldIncludeRule,
|
|
10
|
+
} from './config.js';
|
|
5
11
|
import { mergeSettingsJson, readManifest, writeManifest } from './merge.js';
|
|
6
12
|
|
|
7
13
|
/**
|
|
@@ -114,8 +120,12 @@ export function listTechnologies() {
|
|
|
114
120
|
const skills = fs.existsSync(path.join(sharedPath, 'skills'));
|
|
115
121
|
const rules = fs.existsSync(path.join(sharedPath, 'rules'));
|
|
116
122
|
|
|
117
|
-
console.log(
|
|
118
|
-
|
|
123
|
+
console.log(
|
|
124
|
+
` ${skills ? colors.green('✓') : colors.red('✗')} skills /learning, /review, /spec, /debug, and more`
|
|
125
|
+
);
|
|
126
|
+
console.log(
|
|
127
|
+
` ${rules ? colors.green('✓') : colors.red('✗')} rules security, performance, accessibility`
|
|
128
|
+
);
|
|
119
129
|
console.log('');
|
|
120
130
|
}
|
|
121
131
|
|
|
@@ -136,7 +146,9 @@ export function status(targetDir) {
|
|
|
136
146
|
|
|
137
147
|
console.log(` ${colors.bold('Installed version:')} ${manifest.version}`);
|
|
138
148
|
console.log(` ${colors.bold('Latest version:')} ${VERSION}`);
|
|
139
|
-
console.log(
|
|
149
|
+
console.log(
|
|
150
|
+
` ${colors.bold('Installed at:')} ${new Date(manifest.installedAt).toLocaleString()}`
|
|
151
|
+
);
|
|
140
152
|
console.log('');
|
|
141
153
|
|
|
142
154
|
if (manifest.technologies?.length) {
|
|
@@ -155,7 +167,9 @@ export function status(targetDir) {
|
|
|
155
167
|
}
|
|
156
168
|
|
|
157
169
|
if (manifest.version !== VERSION) {
|
|
158
|
-
console.log(
|
|
170
|
+
console.log(
|
|
171
|
+
` ${colors.yellow('⚠')} Update available! Run ${colors.cyan('ai-rules update')} to update.`
|
|
172
|
+
);
|
|
159
173
|
console.log('');
|
|
160
174
|
}
|
|
161
175
|
|
|
@@ -199,11 +213,11 @@ export function init(techs, options) {
|
|
|
199
213
|
|
|
200
214
|
const settingsPath = path.join(techDir, 'settings.json');
|
|
201
215
|
if (fs.existsSync(settingsPath)) {
|
|
202
|
-
const op = mergeSettingsJson(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
);
|
|
216
|
+
const op = mergeSettingsJson(path.join(targetDir, '.claude', 'settings.json'), settingsPath, {
|
|
217
|
+
dryRun,
|
|
218
|
+
backup,
|
|
219
|
+
targetDir,
|
|
220
|
+
});
|
|
207
221
|
operations.push(op);
|
|
208
222
|
|
|
209
223
|
if (dryRun) {
|
|
@@ -215,11 +229,11 @@ export function init(techs, options) {
|
|
|
215
229
|
|
|
216
230
|
const rulesDir = path.join(techDir, 'rules');
|
|
217
231
|
if (fs.existsSync(rulesDir)) {
|
|
218
|
-
const ops = copyDirRecursive(
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
);
|
|
232
|
+
const ops = copyDirRecursive(rulesDir, path.join(targetDir, '.claude', 'rules', tech), {
|
|
233
|
+
dryRun,
|
|
234
|
+
backup,
|
|
235
|
+
targetDir,
|
|
236
|
+
});
|
|
223
237
|
operations.push(...ops);
|
|
224
238
|
|
|
225
239
|
if (dryRun) {
|
|
@@ -232,11 +246,11 @@ export function init(techs, options) {
|
|
|
232
246
|
if (options.withSkills) {
|
|
233
247
|
const techSkillsDir = path.join(techDir, 'skills');
|
|
234
248
|
if (fs.existsSync(techSkillsDir)) {
|
|
235
|
-
const ops = copySkillsToTarget(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
);
|
|
249
|
+
const ops = copySkillsToTarget(techSkillsDir, path.join(targetDir, '.claude', 'skills'), {
|
|
250
|
+
dryRun,
|
|
251
|
+
backup,
|
|
252
|
+
targetDir,
|
|
253
|
+
});
|
|
240
254
|
operations.push(...ops);
|
|
241
255
|
}
|
|
242
256
|
}
|
|
@@ -248,11 +262,11 @@ export function init(techs, options) {
|
|
|
248
262
|
log.info(`${dryRun ? 'Would install' : 'Installing'} skills...`);
|
|
249
263
|
const skillsDir = path.join(sharedDir, 'skills');
|
|
250
264
|
if (fs.existsSync(skillsDir)) {
|
|
251
|
-
const ops = copySkillsToTarget(
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
);
|
|
265
|
+
const ops = copySkillsToTarget(skillsDir, path.join(targetDir, '.claude', 'skills'), {
|
|
266
|
+
dryRun,
|
|
267
|
+
backup,
|
|
268
|
+
targetDir,
|
|
269
|
+
});
|
|
256
270
|
operations.push(...ops);
|
|
257
271
|
|
|
258
272
|
if (dryRun) {
|