create-claude-workspace 1.1.62 → 1.1.63
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/dist/template/.claude/agents/orchestrator.md +18 -10
- package/dist/template/.claude/templates/.lefthook.yml +12 -0
- package/dist/template/.claude/templates/.prettierrc +12 -0
- package/dist/template/.claude/templates/.stylelintrc.json +15 -0
- package/dist/template/.claude/templates/claude-md.md +14 -173
- package/dist/template/.claude/templates/eslint.config.js +108 -0
- package/package.json +1 -1
|
@@ -91,11 +91,19 @@ At the beginning of EVERY session (including every Ralph Loop iteration):
|
|
|
91
91
|
- Store these in MEMORY.md under a `## Session Config` section if not already present
|
|
92
92
|
- **If Session Config has "TBD" values** (new project before Phase 0): scan `apps/` directory. If apps now exist (Phase 0 completed), update the values. If still empty, keep "TBD" — Phase 0 scaffolding will create them.
|
|
93
93
|
|
|
94
|
-
### 3.
|
|
94
|
+
### 3. Ensure git identity for commits
|
|
95
|
+
- Check `git config user.name` and `git config user.email`. If either is empty, set them:
|
|
96
|
+
```bash
|
|
97
|
+
git config user.name "Claude Code" 2>/dev/null || git config --global user.name "Claude Code"
|
|
98
|
+
git config user.email "claude@localhost" 2>/dev/null || git config --global user.email "claude@localhost"
|
|
99
|
+
```
|
|
100
|
+
- This prevents commits from inheriting the host user's identity. Must be set BEFORE any commit step.
|
|
101
|
+
|
|
102
|
+
### 4. Validate agents are available
|
|
95
103
|
- Check that `.claude/agents/` contains required agent files: `orchestrator.md`, `project-initializer.md`, `ui-engineer.md`, `backend-ts-architect.md`, `senior-code-reviewer.md`, `test-engineer.md`, `devops-integrator.md`, `deployment-engineer.md`, `product-owner.md`, `technical-planner.md`
|
|
96
104
|
- If any critical agent file is missing (architect, reviewer, test-engineer), log to MEMORY.md and STOP — autonomous development requires all agents
|
|
97
105
|
|
|
98
|
-
###
|
|
106
|
+
### 5. Reconcile working state
|
|
99
107
|
Before doing anything, check for unexpected state from user intervention or previous session:
|
|
100
108
|
- **Worktree recovery**: Read MEMORY.md `Current Worktree`. If set, check if the worktree directory exists:
|
|
101
109
|
- Worktree exists + `Current Step` is set → resume from that step (continue working in the worktree)
|
|
@@ -124,25 +132,25 @@ Before doing anything, check for unexpected state from user intervention or prev
|
|
|
124
132
|
- If not merged: create a worktree from this branch (`git worktree add .worktrees/{branch} {branch}`), switch project root back to main (`git checkout main 2>/dev/null || git checkout master`), and resume from the worktree
|
|
125
133
|
- Check if TODO.md or MEMORY.md were manually edited (compare git diff) → accept changes, adjust plan
|
|
126
134
|
|
|
127
|
-
###
|
|
135
|
+
### 6. Check required files exist
|
|
128
136
|
Resolve in THIS order (each depends on the previous):
|
|
129
137
|
1. `CLAUDE.md` missing -> STOP. Run `project-initializer` agent.
|
|
130
138
|
2. `PRODUCT.md` missing -> Delegate to `product-owner` agent. Needs CLAUDE.md.
|
|
131
139
|
3. `TODO.md` missing -> Delegate to `technical-planner` agent. Needs PRODUCT.md + CLAUDE.md.
|
|
132
140
|
4. `MEMORY.md` missing -> Create it (see MEMORY.md template below).
|
|
133
141
|
|
|
134
|
-
###
|
|
142
|
+
### 7. Sync with main branch
|
|
135
143
|
Project root should be on `main`/`master`. If remote exists (`git remote -v | grep origin`):
|
|
136
144
|
```bash
|
|
137
145
|
git pull --rebase origin HEAD
|
|
138
146
|
```
|
|
139
147
|
If no remote, skip this step.
|
|
140
148
|
|
|
141
|
-
###
|
|
149
|
+
### 8. Check git log and structure
|
|
142
150
|
- `git log --oneline -10`
|
|
143
151
|
- Scan current file structure
|
|
144
152
|
|
|
145
|
-
###
|
|
153
|
+
### 9. Detect PLAN.md changes
|
|
146
154
|
If `PLAN.md` exists in the project root, check whether it changed since the last session. This runs AFTER git sync (step 6) to avoid commit conflicts with remote changes.
|
|
147
155
|
|
|
148
156
|
1. Read PLAN.md content
|
|
@@ -174,7 +182,7 @@ If `PLAN.md` exists in the project root, check whether it changed since the last
|
|
|
174
182
|
- `Constraints` → compare coverage threshold against CLAUDE.md code quality section
|
|
175
183
|
- If a PLAN.md value differs from the corresponding project file value, that section "changed"
|
|
176
184
|
|
|
177
|
-
###
|
|
185
|
+
### 10. Retroactive git integration sync
|
|
178
186
|
- **Trigger condition**: remote exists (`git remote -v | grep origin`) AND TODO.md exists with tasks BUT no `<!-- #N -->` markers found in TODO.md AND CLI is available (`gh --version` or `glab --version`) AND auth is valid (`gh auth status` or `glab auth status`)
|
|
179
187
|
- This means work was done locally without git integration (token was missing or platform wasn't set up), and now it's available
|
|
180
188
|
- Delegate to `devops-integrator` agent:
|
|
@@ -190,7 +198,7 @@ If `PLAN.md` exists in the project root, check whether it changed since the last
|
|
|
190
198
|
- Log in MEMORY.md Notes: "Retroactive git sync completed — [N] issues created, [M] marked as done"
|
|
191
199
|
- Skip if any trigger condition is not met (no remote, no TODO.md, markers already present, CLI missing, auth invalid)
|
|
192
200
|
|
|
193
|
-
###
|
|
201
|
+
### 11. Kit version check (CLAUDE.md refresh on upgrade)
|
|
194
202
|
- Read `.claude/.kit-version` — if it exists and differs from MEMORY.md `Kit_Version` (or `Kit_Version` is absent):
|
|
195
203
|
- The `create-claude-workspace` kit was updated. Agent instructions and templates may have changed.
|
|
196
204
|
- Run `/revise-claude-md` to reconcile the project's CLAUDE.md with any new conventions from the updated kit template (`.claude/templates/claude-md.md`).
|
|
@@ -199,13 +207,13 @@ If `PLAN.md` exists in the project root, check whether it changed since the last
|
|
|
199
207
|
- Commit if changes were made: `git add CLAUDE.md MEMORY.md && git commit -m "chore: update CLAUDE.md for kit version [version]"`. Push if remote exists.
|
|
200
208
|
- Skip if `.claude/.kit-version` does not exist.
|
|
201
209
|
|
|
202
|
-
###
|
|
210
|
+
### 12. Ingest external issues (if git integration active)
|
|
203
211
|
- **Only run at phase transitions** — not every invocation
|
|
204
212
|
- Delegate to `devops-integrator` agent: "Run external issue intake — check for new issues on GitHub/GitLab that are not yet in TODO.md. Ingest bugs and feature requests."
|
|
205
213
|
- If new bugs are found with `critical` or `priority::high` label, they become the next task
|
|
206
214
|
- Skip if no git integration or platform is unreachable
|
|
207
215
|
|
|
208
|
-
###
|
|
216
|
+
### 13. One task per invocation
|
|
209
217
|
- Complete exactly ONE task per invocation, then end the session cleanly.
|
|
210
218
|
- The external loop (`autonomous.mjs` or ralph-loop) handles iteration control — you do NOT need to manage capacity, iteration counters, or session bounds.
|
|
211
219
|
- After committing the task (STEP 11) and post-merge (STEP 12), EXIT. Do NOT update MEMORY.md after merge — it was already committed in STEP 11 and arrived on main via merge. Do NOT ask whether to continue, do NOT wait for confirmation, do NOT start another task. Do NOT create any commits after merge.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
pre-commit:
|
|
2
|
+
parallel: true
|
|
3
|
+
commands:
|
|
4
|
+
prettier:
|
|
5
|
+
glob: "*.{ts,html,scss,json,md}"
|
|
6
|
+
run: npx prettier --check {staged_files}
|
|
7
|
+
eslint:
|
|
8
|
+
glob: "*.ts"
|
|
9
|
+
run: npx eslint {staged_files}
|
|
10
|
+
stylelint:
|
|
11
|
+
glob: "*.scss"
|
|
12
|
+
run: npx stylelint {staged_files}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": ["stylelint-config-standard-scss", "stylelint-config-recess-order"],
|
|
3
|
+
"plugins": ["stylelint-order"],
|
|
4
|
+
"rules": {
|
|
5
|
+
"color-no-hex": true,
|
|
6
|
+
"color-named": "never",
|
|
7
|
+
"declaration-no-important": true,
|
|
8
|
+
"max-nesting-depth": [3, { "ignore": ["at-rules", "pseudo-classes"] }],
|
|
9
|
+
"selector-class-pattern": "^(lib-)?[a-z0-9]+(-[a-z0-9]+)*$",
|
|
10
|
+
"scss/selector-no-redundant-nesting-selector": true,
|
|
11
|
+
"scss/at-function-pattern": "^[a-z]([a-z0-9-]*[a-z0-9])?$",
|
|
12
|
+
"scss/at-mixin-pattern": "^[a-z]([a-z0-9-]*[a-z0-9])?$",
|
|
13
|
+
"scss/dollar-variable-pattern": "^[a-z]([a-z0-9-]*[a-z0-9])?$"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -292,182 +292,23 @@ nx affected --target=test -- --coverage # all affected
|
|
|
292
292
|
|
|
293
293
|
### Code Quality & Linting
|
|
294
294
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
// eslint.config.js — root (framework-agnostic base)
|
|
301
|
-
import js from '@eslint/js';
|
|
302
|
-
import tseslint from 'typescript-eslint';
|
|
303
|
-
import nx from '@nx/eslint-plugin';
|
|
304
|
-
import simpleImportSort from 'eslint-plugin-simple-import-sort';
|
|
305
|
-
import preferArrowFunctions from 'eslint-plugin-prefer-arrow-functions';
|
|
306
|
-
|
|
307
|
-
export default [
|
|
308
|
-
{ ignores: ['**/dist', '**/node_modules', '**/.nx'] },
|
|
309
|
-
|
|
310
|
-
// TypeScript files
|
|
311
|
-
{
|
|
312
|
-
files: ['**/*.ts'],
|
|
313
|
-
extends: [
|
|
314
|
-
js.configs.recommended,
|
|
315
|
-
...tseslint.configs.strictTypeChecked,
|
|
316
|
-
...nx.configs['flat/base'],
|
|
317
|
-
...nx.configs['flat/typescript'],
|
|
318
|
-
],
|
|
319
|
-
languageOptions: {
|
|
320
|
-
parserOptions: { projectService: true },
|
|
321
|
-
},
|
|
322
|
-
plugins: {
|
|
323
|
-
'simple-import-sort': simpleImportSort,
|
|
324
|
-
'prefer-arrow-functions': preferArrowFunctions,
|
|
325
|
-
},
|
|
326
|
-
rules: {
|
|
327
|
-
// Modern JS syntax (STRICT)
|
|
328
|
-
'prefer-const': 'error',
|
|
329
|
-
'no-var': 'error',
|
|
330
|
-
'prefer-arrow-callback': 'error',
|
|
331
|
-
'prefer-template': 'error',
|
|
332
|
-
'object-shorthand': 'error',
|
|
333
|
-
'prefer-destructuring': ['error', { object: true, array: false }],
|
|
334
|
-
'prefer-arrow-functions/prefer-arrow-functions': ['error', {
|
|
335
|
-
returnStyle: 'implicit',
|
|
336
|
-
}],
|
|
337
|
-
'max-classes-per-file': ['error', 1],
|
|
338
|
-
'max-depth': ['error', 4],
|
|
339
|
-
'no-restricted-syntax': [
|
|
340
|
-
'error',
|
|
341
|
-
{
|
|
342
|
-
selector: 'CallExpression[callee.property.name="forEach"]',
|
|
343
|
-
message: 'Use for...of instead of .forEach()',
|
|
344
|
-
},
|
|
345
|
-
{
|
|
346
|
-
selector: 'TSAsExpression > TSUnknownKeyword',
|
|
347
|
-
message: 'Do not use `as unknown as T` double-casting. Fix types or use type guards.',
|
|
348
|
-
},
|
|
349
|
-
],
|
|
350
|
-
|
|
351
|
-
// TypeScript strict
|
|
352
|
-
'@typescript-eslint/no-non-null-assertion': 'error',
|
|
353
|
-
'@typescript-eslint/consistent-type-assertions': ['error', {
|
|
354
|
-
assertionStyle: 'as',
|
|
355
|
-
objectLiteralTypeAssertions: 'never',
|
|
356
|
-
}],
|
|
357
|
-
'@typescript-eslint/no-explicit-any': 'error',
|
|
358
|
-
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
|
359
|
-
'@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
|
|
360
|
-
'@typescript-eslint/explicit-function-return-type': ['error', {
|
|
361
|
-
allowExpressions: true,
|
|
362
|
-
allowTypedFunctionExpressions: true,
|
|
363
|
-
}],
|
|
364
|
-
'@typescript-eslint/explicit-member-accessibility': ['error', {
|
|
365
|
-
accessibility: 'explicit',
|
|
366
|
-
overrides: { constructors: 'no-public' },
|
|
367
|
-
}],
|
|
368
|
-
'@typescript-eslint/prefer-readonly': 'error',
|
|
369
|
-
'@typescript-eslint/no-floating-promises': 'error',
|
|
370
|
-
'@typescript-eslint/no-misused-promises': 'error',
|
|
371
|
-
'@typescript-eslint/prefer-for-of': 'error',
|
|
372
|
-
'@typescript-eslint/prefer-nullish-coalescing': 'error',
|
|
373
|
-
'@typescript-eslint/prefer-optional-chain': 'error',
|
|
374
|
-
'@typescript-eslint/strict-boolean-expressions': 'error',
|
|
375
|
-
|
|
376
|
-
// No eslint-disable comments — fix code, don't suppress rules
|
|
377
|
-
'no-warning-comments': ['error', { terms: ['eslint-disable'] }],
|
|
378
|
-
|
|
379
|
-
// Import sorting
|
|
380
|
-
'simple-import-sort/imports': 'error',
|
|
381
|
-
'simple-import-sort/exports': 'error',
|
|
382
|
-
|
|
383
|
-
// Nx module boundaries
|
|
384
|
-
'@nx/enforce-module-boundaries': ['error', {
|
|
385
|
-
enforceBuildableLibDependencies: true,
|
|
386
|
-
allow: [],
|
|
387
|
-
depConstraints: [
|
|
388
|
-
{ sourceTag: 'type:domain', onlyDependOnLibsWithTags: ['type:domain'] },
|
|
389
|
-
{ sourceTag: 'type:business', onlyDependOnLibsWithTags: ['type:domain', 'type:business', 'type:shared'] },
|
|
390
|
-
{ sourceTag: 'type:infrastructure', onlyDependOnLibsWithTags: ['type:domain', 'type:shared'] },
|
|
391
|
-
{ sourceTag: 'type:data-access', onlyDependOnLibsWithTags: ['type:domain', 'type:shared'] },
|
|
392
|
-
{ sourceTag: 'type:ui', onlyDependOnLibsWithTags: ['type:domain', 'type:ui', 'type:shared'] },
|
|
393
|
-
{ sourceTag: 'type:feature', onlyDependOnLibsWithTags: ['type:ui', 'type:data-access', 'type:domain', 'type:shared'] },
|
|
394
|
-
{ sourceTag: 'type:api', onlyDependOnLibsWithTags: ['type:business', 'type:domain', 'type:shared'] },
|
|
395
|
-
{ sourceTag: 'type:app', onlyDependOnLibsWithTags: ['type:feature', 'type:ui', 'type:shared'] },
|
|
396
|
-
],
|
|
397
|
-
}],
|
|
398
|
-
},
|
|
399
|
-
},
|
|
400
|
-
|
|
401
|
-
// Framework-specific rules — see .claude/profiles/frontend.md for additional ESLint config
|
|
402
|
-
// (e.g., Angular template/component rules, React hooks rules, etc.)
|
|
403
|
-
|
|
404
|
-
// Disable type-checked rules for plain JS config files (no tsconfig coverage)
|
|
405
|
-
{ files: ['**/*.js', '**/*.mjs'], ...tseslint.configs.disableTypeChecked },
|
|
406
|
-
];
|
|
407
|
-
```
|
|
295
|
+
Config templates are in `.claude/templates/` — copy to project root during Phase 0 scaffolding:
|
|
296
|
+
- **ESLint**: `.claude/templates/eslint.config.js` → `eslint.config.js` (flat config, `@typescript-eslint/strict-type-checked` + `@nx/eslint-plugin` + `eslint-plugin-simple-import-sort` + `eslint-plugin-prefer-arrow-functions`). Add framework-specific rules from `.claude/profiles/frontend.md`.
|
|
297
|
+
- **Prettier**: `.claude/templates/.prettierrc` → `.prettierrc`
|
|
298
|
+
- **Stylelint**: `.claude/templates/.stylelintrc.json` → `.stylelintrc.json` (SCSS only, forces theme tokens over hardcoded colors)
|
|
299
|
+
- **Pre-commit hooks**: `.claude/templates/.lefthook.yml` → `.lefthook.yml`
|
|
408
300
|
|
|
409
301
|
Each library's `project.json` must declare tags: `"tags": ["type:domain", "scope:auth"]`
|
|
410
302
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
"trailingComma": "all",
|
|
421
|
-
"bracketSpacing": true,
|
|
422
|
-
"arrowParens": "avoid",
|
|
423
|
-
"bracketSameLine": true,
|
|
424
|
-
"singleAttributePerLine": true
|
|
425
|
-
}
|
|
426
|
-
```
|
|
427
|
-
- Single config in root `.prettierrc` — no per-project overrides
|
|
428
|
-
- Runs on commit via pre-commit hooks
|
|
429
|
-
- `eslint-config-prettier` installed to disable conflicting ESLint rules
|
|
430
|
-
- Do NOT use `eslint-plugin-prettier` (couples formatter to linter, slower)
|
|
431
|
-
|
|
432
|
-
**Stylelint** (SCSS quality):
|
|
433
|
-
```jsonc
|
|
434
|
-
// .stylelintrc.json
|
|
435
|
-
{
|
|
436
|
-
"extends": ["stylelint-config-standard-scss", "stylelint-config-recess-order"],
|
|
437
|
-
"plugins": ["stylelint-order"],
|
|
438
|
-
"rules": {
|
|
439
|
-
"color-no-hex": true,
|
|
440
|
-
"color-named": "never",
|
|
441
|
-
"declaration-no-important": true,
|
|
442
|
-
"max-nesting-depth": [3, { "ignore": ["at-rules", "pseudo-classes"] }],
|
|
443
|
-
"selector-class-pattern": "^(lib-)?[a-z0-9]+(-[a-z0-9]+)*$",
|
|
444
|
-
"scss/selector-no-redundant-nesting-selector": true,
|
|
445
|
-
"scss/at-function-pattern": "^[a-z]([a-z0-9-]*[a-z0-9])?$",
|
|
446
|
-
"scss/at-mixin-pattern": "^[a-z]([a-z0-9-]*[a-z0-9])?$",
|
|
447
|
-
"scss/dollar-variable-pattern": "^[a-z]([a-z0-9-]*[a-z0-9])?$"
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
```
|
|
451
|
-
- `color-no-hex` + `color-named: never` → forces use of theme tokens (see frontend profile for theme function names)
|
|
452
|
-
- `stylelint-config-recess-order` for logical property ordering
|
|
453
|
-
- Integrated as Nx target or via pre-commit hooks
|
|
454
|
-
|
|
455
|
-
**Pre-commit hooks** (lefthook or husky + lint-staged):
|
|
456
|
-
```yaml
|
|
457
|
-
# .lefthook.yml
|
|
458
|
-
pre-commit:
|
|
459
|
-
parallel: true
|
|
460
|
-
commands:
|
|
461
|
-
prettier:
|
|
462
|
-
glob: "*.{ts,html,scss,json,md}"
|
|
463
|
-
run: npx prettier --check {staged_files}
|
|
464
|
-
eslint:
|
|
465
|
-
glob: "*.ts"
|
|
466
|
-
run: npx eslint {staged_files}
|
|
467
|
-
stylelint:
|
|
468
|
-
glob: "*.scss"
|
|
469
|
-
run: npx stylelint {staged_files}
|
|
470
|
-
```
|
|
303
|
+
Key rules enforced (do NOT weaken):
|
|
304
|
+
- `prefer-arrow-functions/prefer-arrow-functions` — const arrow over function declarations
|
|
305
|
+
- `max-classes-per-file: 1`, `max-depth: 4`
|
|
306
|
+
- `@typescript-eslint/explicit-member-accessibility` — explicit public/private/protected
|
|
307
|
+
- `@typescript-eslint/prefer-readonly` — readonly where possible
|
|
308
|
+
- `@typescript-eslint/no-non-null-assertion`, `no-explicit-any`, `consistent-type-imports`, `strict-boolean-expressions`
|
|
309
|
+
- `no-warning-comments: ['eslint-disable']` — no eslint-disable comments
|
|
310
|
+
- `@nx/enforce-module-boundaries` — onion architecture layer constraints
|
|
311
|
+
- `eslint-config-prettier` installed to disable conflicting rules. Do NOT use `eslint-plugin-prettier`.
|
|
471
312
|
|
|
472
313
|
**Enforcement:**
|
|
473
314
|
- All three tools run in CI pipeline (fail on violations)
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// eslint.config.js — root (framework-agnostic base)
|
|
2
|
+
// Framework-specific rules (Angular, React, Vue, Svelte) are in .claude/profiles/frontend.md
|
|
3
|
+
import js from '@eslint/js';
|
|
4
|
+
import tseslint from 'typescript-eslint';
|
|
5
|
+
import nx from '@nx/eslint-plugin';
|
|
6
|
+
import simpleImportSort from 'eslint-plugin-simple-import-sort';
|
|
7
|
+
import preferArrowFunctions from 'eslint-plugin-prefer-arrow-functions';
|
|
8
|
+
|
|
9
|
+
export default [
|
|
10
|
+
{ ignores: ['**/dist', '**/node_modules', '**/.nx'] },
|
|
11
|
+
|
|
12
|
+
// TypeScript files
|
|
13
|
+
{
|
|
14
|
+
files: ['**/*.ts'],
|
|
15
|
+
extends: [
|
|
16
|
+
js.configs.recommended,
|
|
17
|
+
...tseslint.configs.strictTypeChecked,
|
|
18
|
+
...nx.configs['flat/base'],
|
|
19
|
+
...nx.configs['flat/typescript'],
|
|
20
|
+
],
|
|
21
|
+
languageOptions: {
|
|
22
|
+
parserOptions: { projectService: true },
|
|
23
|
+
},
|
|
24
|
+
plugins: {
|
|
25
|
+
'simple-import-sort': simpleImportSort,
|
|
26
|
+
'prefer-arrow-functions': preferArrowFunctions,
|
|
27
|
+
},
|
|
28
|
+
rules: {
|
|
29
|
+
// Modern JS syntax (STRICT)
|
|
30
|
+
'prefer-const': 'error',
|
|
31
|
+
'no-var': 'error',
|
|
32
|
+
'prefer-arrow-callback': 'error',
|
|
33
|
+
'prefer-template': 'error',
|
|
34
|
+
'object-shorthand': 'error',
|
|
35
|
+
'prefer-destructuring': ['error', { object: true, array: false }],
|
|
36
|
+
'prefer-arrow-functions/prefer-arrow-functions': ['error', {
|
|
37
|
+
returnStyle: 'implicit',
|
|
38
|
+
}],
|
|
39
|
+
'max-classes-per-file': ['error', 1],
|
|
40
|
+
'max-depth': ['error', 4],
|
|
41
|
+
'no-restricted-syntax': [
|
|
42
|
+
'error',
|
|
43
|
+
{
|
|
44
|
+
selector: 'CallExpression[callee.property.name="forEach"]',
|
|
45
|
+
message: 'Use for...of instead of .forEach()',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
selector: 'TSAsExpression > TSUnknownKeyword',
|
|
49
|
+
message: 'Do not use `as unknown as T` double-casting. Fix types or use type guards.',
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
|
|
53
|
+
// TypeScript strict
|
|
54
|
+
'@typescript-eslint/no-non-null-assertion': 'error',
|
|
55
|
+
'@typescript-eslint/consistent-type-assertions': ['error', {
|
|
56
|
+
assertionStyle: 'as',
|
|
57
|
+
objectLiteralTypeAssertions: 'never',
|
|
58
|
+
}],
|
|
59
|
+
'@typescript-eslint/no-explicit-any': 'error',
|
|
60
|
+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
|
61
|
+
'@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
|
|
62
|
+
'@typescript-eslint/explicit-function-return-type': ['error', {
|
|
63
|
+
allowExpressions: true,
|
|
64
|
+
allowTypedFunctionExpressions: true,
|
|
65
|
+
}],
|
|
66
|
+
'@typescript-eslint/explicit-member-accessibility': ['error', {
|
|
67
|
+
accessibility: 'explicit',
|
|
68
|
+
overrides: { constructors: 'no-public' },
|
|
69
|
+
}],
|
|
70
|
+
'@typescript-eslint/prefer-readonly': 'error',
|
|
71
|
+
'@typescript-eslint/no-floating-promises': 'error',
|
|
72
|
+
'@typescript-eslint/no-misused-promises': 'error',
|
|
73
|
+
'@typescript-eslint/prefer-for-of': 'error',
|
|
74
|
+
'@typescript-eslint/prefer-nullish-coalescing': 'error',
|
|
75
|
+
'@typescript-eslint/prefer-optional-chain': 'error',
|
|
76
|
+
'@typescript-eslint/strict-boolean-expressions': 'error',
|
|
77
|
+
|
|
78
|
+
// No eslint-disable comments — fix code, don't suppress rules
|
|
79
|
+
'no-warning-comments': ['error', { terms: ['eslint-disable'] }],
|
|
80
|
+
|
|
81
|
+
// Import sorting
|
|
82
|
+
'simple-import-sort/imports': 'error',
|
|
83
|
+
'simple-import-sort/exports': 'error',
|
|
84
|
+
|
|
85
|
+
// Nx module boundaries
|
|
86
|
+
'@nx/enforce-module-boundaries': ['error', {
|
|
87
|
+
enforceBuildableLibDependencies: true,
|
|
88
|
+
allow: [],
|
|
89
|
+
depConstraints: [
|
|
90
|
+
{ sourceTag: 'type:domain', onlyDependOnLibsWithTags: ['type:domain'] },
|
|
91
|
+
{ sourceTag: 'type:business', onlyDependOnLibsWithTags: ['type:domain', 'type:business', 'type:shared'] },
|
|
92
|
+
{ sourceTag: 'type:infrastructure', onlyDependOnLibsWithTags: ['type:domain', 'type:shared'] },
|
|
93
|
+
{ sourceTag: 'type:data-access', onlyDependOnLibsWithTags: ['type:domain', 'type:shared'] },
|
|
94
|
+
{ sourceTag: 'type:ui', onlyDependOnLibsWithTags: ['type:domain', 'type:ui', 'type:shared'] },
|
|
95
|
+
{ sourceTag: 'type:feature', onlyDependOnLibsWithTags: ['type:ui', 'type:data-access', 'type:domain', 'type:shared'] },
|
|
96
|
+
{ sourceTag: 'type:api', onlyDependOnLibsWithTags: ['type:business', 'type:domain', 'type:shared'] },
|
|
97
|
+
{ sourceTag: 'type:app', onlyDependOnLibsWithTags: ['type:feature', 'type:ui', 'type:shared'] },
|
|
98
|
+
],
|
|
99
|
+
}],
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
// Framework-specific rules — see .claude/profiles/frontend.md for additional ESLint config
|
|
104
|
+
// (e.g., Angular template/component rules, React hooks rules, etc.)
|
|
105
|
+
|
|
106
|
+
// Disable type-checked rules for plain JS config files (no tsconfig coverage)
|
|
107
|
+
{ files: ['**/*.js', '**/*.mjs'], ...tseslint.configs.disableTypeChecked },
|
|
108
|
+
];
|