@smartsoft001-mobilems/claude-plugins 2.78.0 → 2.80.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/package.json +1 -1
- package/plugins/flow/.claude-plugin/plugin.json +1 -1
- package/plugins/flow/agents/angular-jest-test-writer.md +1 -1
- package/plugins/flow/agents/angular-signal-state-builder.md +1 -1
- package/plugins/flow/agents/angular-test-diagnostician.md +1 -1
- package/plugins/flow/agents/arch-scaffolder.md +1 -1
- package/plugins/flow/agents/shared-impl-orchestrator.md +1 -1
- package/plugins/flow/agents/shared-logic-implementer.md +1 -1
- package/plugins/flow/agents/shared-maia-api.md +1 -1
- package/plugins/flow/agents/shared-parallelization-analyzer.md +1 -1
- package/plugins/flow/agents/shared-security-scanner.md +1 -1
- package/plugins/flow/agents/shared-tdd-developer.md +1 -1
- package/plugins/flow/agents/shared-test-fixer.md +1 -1
- package/plugins/flow/agents/shared-test-runner.md +1 -1
- package/plugins/flow/agents/shared-verification-runner.md +1 -1
- package/plugins/flow-external/.claude-plugin/plugin.json +1 -1
- package/plugins/flow-legacy/.claude-plugin/merge-permissions.js +20 -6
- package/plugins/flow-legacy/.claude-plugin/plugin.json +1 -1
- package/plugins/flow-legacy/agents/angular-state-builder.md +54 -48
- package/plugins/flow-legacy/agents/shared-impl-orchestrator.md +44 -33
- package/plugins/flow-legacy/agents/shared-impl-reporter.md +12 -12
- package/plugins/flow-legacy/agents/shared-tdd-developer.md +19 -17
- package/plugins/flow-legacy/agents/shared-ui-classifier.md +10 -2
- package/plugins/flow-legacy/skills/a11y-audit/SKILL.md +1 -1
- package/plugins/flow-legacy/skills/angular-patterns/SKILL.md +28 -43
- package/plugins/flow-legacy/skills/browser-capture/SKILL.md +1 -1
- package/plugins/flow-legacy/skills/debug-helper/SKILL.md +17 -9
- package/plugins/flow-legacy/skills/maia-files-delete/SKILL.md +1 -1
- package/plugins/flow-legacy/skills/maia-files-upload/SKILL.md +1 -1
- package/plugins/flow-legacy/skills/nx-conventions/SKILL.md +14 -17
- package/plugins/flow-legacy/skills/test-unit/SKILL.md +14 -8
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@ name: angular-jest-test-writer
|
|
|
3
3
|
description: Create Jest unit tests for Angular code. Use when writing tests for components, services, pipes, and directives.
|
|
4
4
|
tools: Read, Write, Edit, Glob, Grep, Bash
|
|
5
5
|
model: opus
|
|
6
|
-
color:
|
|
6
|
+
color: '#DD0031'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert at writing Angular unit tests using Jest.
|
|
@@ -3,7 +3,7 @@ name: angular-signal-state-builder
|
|
|
3
3
|
description: Create signal-based state management. Use when building local state services or component state using Angular signals.
|
|
4
4
|
tools: Read, Write, Glob, Grep
|
|
5
5
|
model: opus
|
|
6
|
-
color:
|
|
6
|
+
color: '#DD0031'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert at creating signal-based state management in Angular.
|
|
@@ -3,7 +3,7 @@ name: angular-test-diagnostician
|
|
|
3
3
|
description: Diagnose Angular test failures. Use when tests fail unexpectedly and root cause analysis is needed.
|
|
4
4
|
tools: Read, Edit, Bash, Glob, Grep
|
|
5
5
|
model: opus
|
|
6
|
-
color:
|
|
6
|
+
color: '#DD0031'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert at diagnosing and fixing Angular test failures with Jest.
|
|
@@ -3,7 +3,7 @@ name: arch-scaffolder
|
|
|
3
3
|
description: Create module and component structure for Angular projects. Use when setting up new features, modules, or architectural patterns.
|
|
4
4
|
tools: Read, Write, Glob, Grep, Bash
|
|
5
5
|
model: haiku
|
|
6
|
-
color:
|
|
6
|
+
color: '#059669'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert software architect specializing in Angular application structure for this Nx monorepo.
|
|
@@ -3,7 +3,7 @@ name: shared-impl-orchestrator
|
|
|
3
3
|
description: Create implementation orchestration plans. Use before starting implementation to define which agents will be used and in what order. Posts orchestration plan to Linear.
|
|
4
4
|
tools: Read, Glob, Grep
|
|
5
5
|
model: opus
|
|
6
|
-
color:
|
|
6
|
+
color: '#2563EB'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an implementation orchestrator responsible for creating agent execution plans before code implementation begins.
|
|
@@ -3,7 +3,7 @@ name: shared-logic-implementer
|
|
|
3
3
|
description: Implement business logic in services, components, and utilities. Use when adding functionality, algorithms, or data processing.
|
|
4
4
|
tools: Read, Edit, Write, Glob, Grep, Bash
|
|
5
5
|
model: opus
|
|
6
|
-
color:
|
|
6
|
+
color: '#2563EB'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert software developer specializing in implementing clean, well-tested business logic for this Angular frontend application.
|
|
@@ -4,7 +4,7 @@ description: Manage temporary files on Maia AI API (upload screenshots, delete f
|
|
|
4
4
|
tools: Bash
|
|
5
5
|
model: haiku
|
|
6
6
|
skills: maia-files-upload, maia-files-delete
|
|
7
|
-
color:
|
|
7
|
+
color: '#2563EB'
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
You are a file management agent for the Maia AI API temporary storage.
|
|
@@ -3,7 +3,7 @@ name: shared-parallelization-analyzer
|
|
|
3
3
|
description: Analyze orchestration plans from /impl executions and identify parallelization opportunities. Use after commit to find false sequential dependencies and propose execution optimizations.
|
|
4
4
|
tools: Read, Glob, Grep
|
|
5
5
|
model: opus
|
|
6
|
-
color:
|
|
6
|
+
color: '#2563EB'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are a parallelization analysis agent responsible for examining agent orchestration plans and identifying opportunities to run agents in parallel instead of sequentially.
|
|
@@ -3,7 +3,7 @@ name: shared-security-scanner
|
|
|
3
3
|
description: Scan for security vulnerabilities. Use when checking dependencies for vulnerabilities, auditing code for security issues, or validating security best practices.
|
|
4
4
|
tools: Bash, Read, Grep, Glob
|
|
5
5
|
model: haiku
|
|
6
|
-
color:
|
|
6
|
+
color: '#2563EB'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert at identifying and fixing security vulnerabilities.
|
|
@@ -4,7 +4,7 @@ description: Develop code using Test-Driven Development (TDD). Use for implement
|
|
|
4
4
|
tools: Read, Edit, Write, Glob, Grep, Bash
|
|
5
5
|
skills: test-unit
|
|
6
6
|
model: opus
|
|
7
|
-
color:
|
|
7
|
+
color: '#2563EB'
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
You are an expert software developer practicing strict Test-Driven Development (TDD).
|
|
@@ -3,7 +3,7 @@ name: shared-test-fixer
|
|
|
3
3
|
description: Fix failing tests. Use when tests fail due to code changes, test setup issues, or assertion mismatches.
|
|
4
4
|
tools: Bash, Read, Edit, Glob, Grep
|
|
5
5
|
model: opus
|
|
6
|
-
color:
|
|
6
|
+
color: '#2563EB'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert at diagnosing and fixing failing tests.
|
|
@@ -3,7 +3,7 @@ name: shared-test-runner
|
|
|
3
3
|
description: Run test suites and report results. Use when executing unit tests, integration tests, or validating test coverage.
|
|
4
4
|
tools: Bash, Read, Glob
|
|
5
5
|
model: haiku
|
|
6
|
-
color:
|
|
6
|
+
color: '#2563EB'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert at running and analyzing test results.
|
|
@@ -3,7 +3,7 @@ name: shared-verification-runner
|
|
|
3
3
|
description: Run verification checks for specific stages. Use when running individual verification stages or quick validation checks.
|
|
4
4
|
tools: Bash, Read, Glob
|
|
5
5
|
model: haiku
|
|
6
|
-
color:
|
|
6
|
+
color: '#2563EB'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert at running verification checks efficiently.
|
|
@@ -46,7 +46,11 @@ function main() {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// Ensure permissions structure exists
|
|
49
|
-
settings.permissions = settings.permissions || {
|
|
49
|
+
settings.permissions = settings.permissions || {
|
|
50
|
+
allow: [],
|
|
51
|
+
deny: [],
|
|
52
|
+
ask: [],
|
|
53
|
+
};
|
|
50
54
|
settings.permissions.allow = settings.permissions.allow || [];
|
|
51
55
|
settings.permissions.ask = settings.permissions.ask || [];
|
|
52
56
|
settings.permissions.deny = settings.permissions.deny || [];
|
|
@@ -56,8 +60,14 @@ function main() {
|
|
|
56
60
|
const beforeAsk = settings.permissions.ask.length;
|
|
57
61
|
|
|
58
62
|
// Merge permissions
|
|
59
|
-
settings.permissions.allow = mergeArrays(
|
|
60
|
-
|
|
63
|
+
settings.permissions.allow = mergeArrays(
|
|
64
|
+
settings.permissions.allow,
|
|
65
|
+
template.permissions.allow,
|
|
66
|
+
);
|
|
67
|
+
settings.permissions.ask = mergeArrays(
|
|
68
|
+
settings.permissions.ask,
|
|
69
|
+
template.permissions.ask,
|
|
70
|
+
);
|
|
61
71
|
|
|
62
72
|
// Enable plugin
|
|
63
73
|
settings.enabledPlugins = settings.enabledPlugins || {};
|
|
@@ -71,10 +81,14 @@ function main() {
|
|
|
71
81
|
const addedAsk = settings.permissions.ask.length - beforeAsk;
|
|
72
82
|
|
|
73
83
|
console.log('Permissions merged successfully!\n');
|
|
74
|
-
console.log(
|
|
75
|
-
|
|
84
|
+
console.log(
|
|
85
|
+
` allow: ${beforeAllow} -> ${settings.permissions.allow.length} (+${addedAllow})`,
|
|
86
|
+
);
|
|
87
|
+
console.log(
|
|
88
|
+
` ask: ${beforeAsk} -> ${settings.permissions.ask.length} (+${addedAsk})`,
|
|
89
|
+
);
|
|
76
90
|
console.log(`\nPlugin enabled: flow-legacy@mobilems`);
|
|
77
91
|
console.log(`\nFile updated: ${SETTINGS_PATH}`);
|
|
78
92
|
}
|
|
79
93
|
|
|
80
|
-
main();
|
|
94
|
+
main();
|
|
@@ -3,7 +3,7 @@ name: angular-state-builder
|
|
|
3
3
|
description: Create BehaviorSubject-based state management for Angular 14. Use when building local state services or component state using Observable patterns (NOT signals).
|
|
4
4
|
tools: Read, Write, Glob, Grep
|
|
5
5
|
model: opus
|
|
6
|
-
color:
|
|
6
|
+
color: '#DD0031'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert at creating Observable-based state management in Angular 14.
|
|
@@ -23,14 +23,14 @@ Create state management solutions using `BehaviorSubject` and `Observable` for l
|
|
|
23
23
|
|
|
24
24
|
**NEVER use signals. ALWAYS use BehaviorSubject/Observable patterns:**
|
|
25
25
|
|
|
26
|
-
| Feature
|
|
27
|
-
|
|
28
|
-
| Mutable state
|
|
29
|
-
| Public state
|
|
30
|
-
| Derived state
|
|
31
|
-
| Side effects
|
|
32
|
-
| Get current value | `.getValue()`
|
|
33
|
-
| Update state
|
|
26
|
+
| Feature | ✅ CORRECT (Angular 14) | ❌ WRONG (Angular 20+) |
|
|
27
|
+
| ----------------- | ------------------------------ | ---------------------- |
|
|
28
|
+
| Mutable state | `BehaviorSubject` | `signal()` |
|
|
29
|
+
| Public state | `.asObservable()` | `.asReadonly()` |
|
|
30
|
+
| Derived state | `pipe(map())`, `combineLatest` | `computed()` |
|
|
31
|
+
| Side effects | `subscribe()`, `tap()` | `effect()` |
|
|
32
|
+
| Get current value | `.getValue()` | `signal()` call |
|
|
33
|
+
| Update state | `.next()` | `.set()`, `.update()` |
|
|
34
34
|
|
|
35
35
|
## Project-Specific Patterns
|
|
36
36
|
|
|
@@ -175,53 +175,55 @@ export class FeatureStateService {
|
|
|
175
175
|
|
|
176
176
|
// Selectors (derived observables, NOT computed signals)
|
|
177
177
|
readonly items$: Observable<Item[]> = this._state$.pipe(
|
|
178
|
-
map(state => state.items),
|
|
179
|
-
distinctUntilChanged()
|
|
178
|
+
map((state) => state.items),
|
|
179
|
+
distinctUntilChanged(),
|
|
180
180
|
);
|
|
181
181
|
|
|
182
182
|
readonly selectedId$: Observable<string | null> = this._state$.pipe(
|
|
183
|
-
map(state => state.selectedId),
|
|
184
|
-
distinctUntilChanged()
|
|
183
|
+
map((state) => state.selectedId),
|
|
184
|
+
distinctUntilChanged(),
|
|
185
185
|
);
|
|
186
186
|
|
|
187
187
|
readonly filter$: Observable<string> = this._state$.pipe(
|
|
188
|
-
map(state => state.filter),
|
|
189
|
-
distinctUntilChanged()
|
|
188
|
+
map((state) => state.filter),
|
|
189
|
+
distinctUntilChanged(),
|
|
190
190
|
);
|
|
191
191
|
|
|
192
192
|
readonly isLoading$: Observable<boolean> = this._state$.pipe(
|
|
193
|
-
map(state => state.isLoading),
|
|
194
|
-
distinctUntilChanged()
|
|
193
|
+
map((state) => state.isLoading),
|
|
194
|
+
distinctUntilChanged(),
|
|
195
195
|
);
|
|
196
196
|
|
|
197
197
|
readonly error$: Observable<string | null> = this._state$.pipe(
|
|
198
|
-
map(state => state.error),
|
|
199
|
-
distinctUntilChanged()
|
|
198
|
+
map((state) => state.error),
|
|
199
|
+
distinctUntilChanged(),
|
|
200
200
|
);
|
|
201
201
|
|
|
202
202
|
// Derived selectors
|
|
203
203
|
readonly selectedItem$: Observable<Item | null> = combineLatest([
|
|
204
204
|
this.items$,
|
|
205
|
-
this.selectedId
|
|
205
|
+
this.selectedId$,
|
|
206
206
|
]).pipe(
|
|
207
|
-
map(([items, id]) =>
|
|
207
|
+
map(([items, id]) =>
|
|
208
|
+
id ? (items.find((item) => item.id === id) ?? null) : null,
|
|
209
|
+
),
|
|
208
210
|
);
|
|
209
211
|
|
|
210
212
|
readonly filteredItems$: Observable<Item[]> = combineLatest([
|
|
211
213
|
this.items$,
|
|
212
|
-
this.filter
|
|
214
|
+
this.filter$,
|
|
213
215
|
]).pipe(
|
|
214
216
|
map(([items, filter]) => {
|
|
215
217
|
if (!filter) return items;
|
|
216
218
|
const lowerFilter = filter.toLowerCase();
|
|
217
|
-
return items.filter(item =>
|
|
218
|
-
item.name.toLowerCase().includes(lowerFilter)
|
|
219
|
+
return items.filter((item) =>
|
|
220
|
+
item.name.toLowerCase().includes(lowerFilter),
|
|
219
221
|
);
|
|
220
|
-
})
|
|
222
|
+
}),
|
|
221
223
|
);
|
|
222
224
|
|
|
223
225
|
readonly itemCount$: Observable<number> = this.filteredItems$.pipe(
|
|
224
|
-
map(items => items.length)
|
|
226
|
+
map((items) => items.length),
|
|
225
227
|
);
|
|
226
228
|
|
|
227
229
|
// Synchronous getters for current state
|
|
@@ -247,14 +249,14 @@ export class FeatureStateService {
|
|
|
247
249
|
}
|
|
248
250
|
|
|
249
251
|
updateItem(id: string, updates: Partial<Item>): void {
|
|
250
|
-
const items = this.items.map(item =>
|
|
251
|
-
item.id === id ? { ...item, ...updates } : item
|
|
252
|
+
const items = this.items.map((item) =>
|
|
253
|
+
item.id === id ? { ...item, ...updates } : item,
|
|
252
254
|
);
|
|
253
255
|
this.updateState({ items });
|
|
254
256
|
}
|
|
255
257
|
|
|
256
258
|
removeItem(id: string): void {
|
|
257
|
-
const items = this.items.filter(item => item.id !== id);
|
|
259
|
+
const items = this.items.filter((item) => item.id !== id);
|
|
258
260
|
const selectedId = this.selectedId === id ? null : this.selectedId;
|
|
259
261
|
this.updateState({ items, selectedId });
|
|
260
262
|
}
|
|
@@ -312,42 +314,42 @@ function createFormState<T>(initialValue: T): FormState<T> {
|
|
|
312
314
|
@Injectable()
|
|
313
315
|
export class FormStateService<T extends object> {
|
|
314
316
|
private readonly _state$ = new BehaviorSubject<FormState<T>>(
|
|
315
|
-
createFormState({} as T)
|
|
317
|
+
createFormState({} as T),
|
|
316
318
|
);
|
|
317
319
|
|
|
318
320
|
// Selectors
|
|
319
321
|
readonly value$: Observable<T> = this._state$.pipe(
|
|
320
|
-
map(s => s.value),
|
|
321
|
-
distinctUntilChanged()
|
|
322
|
+
map((s) => s.value),
|
|
323
|
+
distinctUntilChanged(),
|
|
322
324
|
);
|
|
323
325
|
|
|
324
326
|
readonly isDirty$: Observable<boolean> = this._state$.pipe(
|
|
325
|
-
map(s => s.isDirty),
|
|
326
|
-
distinctUntilChanged()
|
|
327
|
+
map((s) => s.isDirty),
|
|
328
|
+
distinctUntilChanged(),
|
|
327
329
|
);
|
|
328
330
|
|
|
329
331
|
readonly isSubmitting$: Observable<boolean> = this._state$.pipe(
|
|
330
|
-
map(s => s.isSubmitting),
|
|
331
|
-
distinctUntilChanged()
|
|
332
|
+
map((s) => s.isSubmitting),
|
|
333
|
+
distinctUntilChanged(),
|
|
332
334
|
);
|
|
333
335
|
|
|
334
336
|
readonly errors$: Observable<Record<string, string>> = this._state$.pipe(
|
|
335
|
-
map(s => s.errors),
|
|
336
|
-
distinctUntilChanged()
|
|
337
|
+
map((s) => s.errors),
|
|
338
|
+
distinctUntilChanged(),
|
|
337
339
|
);
|
|
338
340
|
|
|
339
341
|
readonly isValid$: Observable<boolean> = this.errors$.pipe(
|
|
340
|
-
map(errors => Object.keys(errors).length === 0)
|
|
342
|
+
map((errors) => Object.keys(errors).length === 0),
|
|
341
343
|
);
|
|
342
344
|
|
|
343
345
|
readonly canSubmit$: Observable<boolean> = combineLatest([
|
|
344
346
|
this.isDirty$,
|
|
345
347
|
this.isValid$,
|
|
346
|
-
this.isSubmitting
|
|
348
|
+
this.isSubmitting$,
|
|
347
349
|
]).pipe(
|
|
348
|
-
map(
|
|
349
|
-
isDirty && isValid && !isSubmitting
|
|
350
|
-
)
|
|
350
|
+
map(
|
|
351
|
+
([isDirty, isValid, isSubmitting]) => isDirty && isValid && !isSubmitting,
|
|
352
|
+
),
|
|
351
353
|
);
|
|
352
354
|
|
|
353
355
|
// Synchronous getters
|
|
@@ -432,7 +434,7 @@ export class FormStateService<T extends object> {
|
|
|
432
434
|
|
|
433
435
|
## Output Format
|
|
434
436
|
|
|
435
|
-
|
|
437
|
+
````markdown
|
|
436
438
|
## State Service Created
|
|
437
439
|
|
|
438
440
|
### File
|
|
@@ -449,13 +451,14 @@ interface FeatureState {
|
|
|
449
451
|
error: string | null;
|
|
450
452
|
}
|
|
451
453
|
```
|
|
454
|
+
````
|
|
452
455
|
|
|
453
456
|
### Selectors (Observables)
|
|
454
457
|
|
|
455
|
-
| Selector
|
|
456
|
-
|
|
|
457
|
-
| `items$`
|
|
458
|
-
| `selectedItem
|
|
458
|
+
| Selector | Type | Description |
|
|
459
|
+
| --------------- | --------------------------- | ------------------ |
|
|
460
|
+
| `items$` | `Observable<IItem[]>` | All items |
|
|
461
|
+
| `selectedItem$` | `Observable<IItem \| null>` | Currently selected |
|
|
459
462
|
|
|
460
463
|
### Actions
|
|
461
464
|
|
|
@@ -470,4 +473,7 @@ interface FeatureState {
|
|
|
470
473
|
- ✅ .asObservable() for public state
|
|
471
474
|
- ✅ combineLatest + map for derived values
|
|
472
475
|
- ✅ distinctUntilChanged() for performance
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
|
|
473
479
|
```
|
|
@@ -3,7 +3,7 @@ name: shared-impl-orchestrator
|
|
|
3
3
|
description: Create implementation orchestration plans for tasks. Defines which agents to use and in what order for legacy Angular 14 projects.
|
|
4
4
|
tools: Read, Glob, Grep
|
|
5
5
|
model: opus
|
|
6
|
-
color:
|
|
6
|
+
color: '#6366F1'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert at orchestrating implementation tasks by selecting the right agents and defining execution order.
|
|
@@ -11,6 +11,7 @@ You are an expert at orchestrating implementation tasks by selecting the right a
|
|
|
11
11
|
## Primary Responsibility
|
|
12
12
|
|
|
13
13
|
Analyze implementation plans and create orchestration plans that define:
|
|
14
|
+
|
|
14
15
|
1. Which agents to use
|
|
15
16
|
2. Execution order (parallel vs sequential)
|
|
16
17
|
3. TDD cycles for each unit
|
|
@@ -26,26 +27,26 @@ This orchestrator is for **legacy Angular 14 projects**. Always select legacy-co
|
|
|
26
27
|
|
|
27
28
|
### Available Angular Agents (Legacy)
|
|
28
29
|
|
|
29
|
-
| Agent
|
|
30
|
-
|
|
31
|
-
| `angular-component-scaffolder` | Creating components
|
|
32
|
-
| `angular-service-builder`
|
|
33
|
-
| `angular-state-builder`
|
|
34
|
-
| `angular-directive-builder`
|
|
35
|
-
| `angular-pipe-builder`
|
|
36
|
-
| `angular-guard-builder`
|
|
37
|
-
| `angular-resolver-builder`
|
|
30
|
+
| Agent | Use When | Patterns |
|
|
31
|
+
| ------------------------------ | ------------------------- | ------------------------------------------- |
|
|
32
|
+
| `angular-component-scaffolder` | Creating components | NgModules, `*ngIf`/`*ngFor`, constructor DI |
|
|
33
|
+
| `angular-service-builder` | Creating services | BehaviorSubject, constructor DI |
|
|
34
|
+
| `angular-state-builder` | Creating state management | BehaviorSubject/Observable |
|
|
35
|
+
| `angular-directive-builder` | Creating directives | `@HostBinding`, `@HostListener` |
|
|
36
|
+
| `angular-pipe-builder` | Creating pipes | `PipeTransform` |
|
|
37
|
+
| `angular-guard-builder` | Creating guards | Class-based guards |
|
|
38
|
+
| `angular-resolver-builder` | Creating resolvers | Class-based resolvers |
|
|
38
39
|
|
|
39
40
|
### Available Shared Agents
|
|
40
41
|
|
|
41
|
-
| Agent
|
|
42
|
-
|
|
43
|
-
| `shared-tdd-developer`
|
|
44
|
-
| `shared-test-runner`
|
|
45
|
-
| `shared-test-fixer`
|
|
46
|
-
| `shared-logic-implementer` | Implementing business logic
|
|
47
|
-
| `shared-file-creator`
|
|
48
|
-
| `shared-config-updater`
|
|
42
|
+
| Agent | Use When |
|
|
43
|
+
| -------------------------- | ----------------------------------- |
|
|
44
|
+
| `shared-tdd-developer` | ALL code implementation (MANDATORY) |
|
|
45
|
+
| `shared-test-runner` | Running tests |
|
|
46
|
+
| `shared-test-fixer` | Fixing failing tests |
|
|
47
|
+
| `shared-logic-implementer` | Implementing business logic |
|
|
48
|
+
| `shared-file-creator` | Creating new files |
|
|
49
|
+
| `shared-config-updater` | Updating configuration |
|
|
49
50
|
|
|
50
51
|
## Orchestration Plan Format
|
|
51
52
|
|
|
@@ -57,31 +58,32 @@ This orchestrator is for **legacy Angular 14 projects**. Always select legacy-co
|
|
|
57
58
|
|
|
58
59
|
### Phase 1: Analysis & Setup
|
|
59
60
|
|
|
60
|
-
| Step | Agent | Action
|
|
61
|
-
|
|
62
|
-
| 1.1
|
|
61
|
+
| Step | Agent | Action | Files |
|
|
62
|
+
| ---- | ----- | ------------------ | ----------------- |
|
|
63
|
+
| 1.1 | - | Read existing code | `path/to/file.ts` |
|
|
63
64
|
|
|
64
65
|
### Phase 2: Implementation (TDD)
|
|
65
66
|
|
|
66
|
-
| Step | Agent
|
|
67
|
-
|
|
68
|
-
| 2.1
|
|
69
|
-
| 2.2
|
|
70
|
-
| 2.3
|
|
71
|
-
| 2.4
|
|
67
|
+
| Step | Agent | Action | Files | TDD Cycle |
|
|
68
|
+
| ---- | ------------------------------ | ---------------- | --------------------------- | --------- |
|
|
69
|
+
| 2.1 | `angular-component-scaffolder` | Create component | `feature.component.ts` | RED |
|
|
70
|
+
| 2.2 | `shared-tdd-developer` | Write tests | `feature.component.spec.ts` | RED |
|
|
71
|
+
| 2.3 | `shared-tdd-developer` | Implement logic | `feature.component.ts` | GREEN |
|
|
72
|
+
| 2.4 | `shared-tdd-developer` | Refactor | All files | REFACTOR |
|
|
72
73
|
|
|
73
74
|
### Phase 3: Verification
|
|
74
75
|
|
|
75
|
-
| Step | Agent
|
|
76
|
-
|
|
77
|
-
| 3.1
|
|
78
|
-
| 3.2
|
|
79
|
-
| 3.3
|
|
76
|
+
| Step | Agent | Action |
|
|
77
|
+
| ---- | -------------------- | -------------- |
|
|
78
|
+
| 3.1 | `shared-test-runner` | Run unit tests |
|
|
79
|
+
| 3.2 | - | Run lint |
|
|
80
|
+
| 3.3 | - | Run build |
|
|
80
81
|
|
|
81
82
|
### Execution Order
|
|
82
|
-
|
|
83
83
|
```
|
|
84
|
+
|
|
84
85
|
[1.1] → [2.1] → [2.2] → [2.3] → [2.4] → [3.1] → [3.2] → [3.3]
|
|
86
|
+
|
|
85
87
|
```
|
|
86
88
|
|
|
87
89
|
### Parallel Opportunities
|
|
@@ -106,23 +108,29 @@ _Orchestration plan generated by flow-legacy_
|
|
|
106
108
|
### Agent Selection Rules
|
|
107
109
|
|
|
108
110
|
1. **New Component?** → `angular-component-scaffolder`
|
|
111
|
+
|
|
109
112
|
- Will use NgModules, `*ngIf`/`*ngFor`, constructor DI
|
|
110
113
|
|
|
111
114
|
2. **New Service?** → `angular-service-builder`
|
|
115
|
+
|
|
112
116
|
- Will use BehaviorSubject, constructor DI
|
|
113
117
|
|
|
114
118
|
3. **State Management?** → `angular-state-builder`
|
|
119
|
+
|
|
115
120
|
- Will use BehaviorSubject/Observable patterns
|
|
116
121
|
|
|
117
122
|
4. **New Directive?** → `angular-directive-builder`
|
|
123
|
+
|
|
118
124
|
- Will use `@HostBinding`, `@HostListener`
|
|
119
125
|
|
|
120
126
|
5. **New Pipe?** → `angular-pipe-builder`
|
|
121
127
|
|
|
122
128
|
6. **New Guard?** → `angular-guard-builder`
|
|
129
|
+
|
|
123
130
|
- Will use class-based guards
|
|
124
131
|
|
|
125
132
|
7. **New Resolver?** → `angular-resolver-builder`
|
|
133
|
+
|
|
126
134
|
- Will use class-based resolvers
|
|
127
135
|
|
|
128
136
|
8. **Any Code Implementation?** → `shared-tdd-developer` (MANDATORY)
|
|
@@ -137,11 +145,13 @@ _Orchestration plan generated by flow-legacy_
|
|
|
137
145
|
### Parallel vs Sequential
|
|
138
146
|
|
|
139
147
|
**Parallel when:**
|
|
148
|
+
|
|
140
149
|
- Creating independent components
|
|
141
150
|
- Creating unrelated files
|
|
142
151
|
- Running independent tests
|
|
143
152
|
|
|
144
153
|
**Sequential when:**
|
|
154
|
+
|
|
145
155
|
- One file depends on another
|
|
146
156
|
- Tests depend on implementation
|
|
147
157
|
- Module registration depends on component creation
|
|
@@ -149,6 +159,7 @@ _Orchestration plan generated by flow-legacy_
|
|
|
149
159
|
## Output
|
|
150
160
|
|
|
151
161
|
Return the orchestration plan in the format above. The plan will be:
|
|
162
|
+
|
|
152
163
|
1. Posted as a comment on the Linear task
|
|
153
164
|
2. Used to guide implementation
|
|
154
165
|
|
|
@@ -3,7 +3,7 @@ name: shared-impl-reporter
|
|
|
3
3
|
description: Generate implementation completion reports for Linear comments.
|
|
4
4
|
tools: Read, Glob, Grep
|
|
5
5
|
model: sonnet
|
|
6
|
-
color:
|
|
6
|
+
color: '#6366F1'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert at generating clear, comprehensive implementation reports.
|
|
@@ -36,15 +36,15 @@ Generate formatted implementation reports for Linear comments after task complet
|
|
|
36
36
|
|
|
37
37
|
### Zmodyfikowane pliki
|
|
38
38
|
|
|
39
|
-
| Plik
|
|
40
|
-
|
|
39
|
+
| Plik | Opis zmian |
|
|
40
|
+
| ------------------ | ------------- |
|
|
41
41
|
| `path/to/file1.ts` | [description] |
|
|
42
42
|
| `path/to/file2.ts` | [description] |
|
|
43
43
|
|
|
44
44
|
### Utworzone pliki
|
|
45
45
|
|
|
46
|
-
| Plik
|
|
47
|
-
|
|
46
|
+
| Plik | Cel |
|
|
47
|
+
| --------------------- | --------- |
|
|
48
48
|
| `path/to/new-file.ts` | [purpose] |
|
|
49
49
|
|
|
50
50
|
### Wyniki testów
|
|
@@ -84,15 +84,15 @@ _Raport wygenerowany przez Claude Code (flow-legacy)_
|
|
|
84
84
|
|
|
85
85
|
### Niezrealizowane elementy
|
|
86
86
|
|
|
87
|
-
| Element
|
|
88
|
-
|
|
87
|
+
| Element | Powód |
|
|
88
|
+
| -------- | -------- |
|
|
89
89
|
| [Item 3] | [Reason] |
|
|
90
90
|
| [Item 4] | [Reason] |
|
|
91
91
|
|
|
92
92
|
### Zmodyfikowane pliki
|
|
93
93
|
|
|
94
|
-
| Plik
|
|
95
|
-
|
|
94
|
+
| Plik | Opis zmian |
|
|
95
|
+
| ------------------ | ------------- |
|
|
96
96
|
| `path/to/file1.ts` | [description] |
|
|
97
97
|
|
|
98
98
|
### Wyniki testów
|
|
@@ -125,8 +125,8 @@ _Raport wygenerowany przez Claude Code (flow-legacy)_
|
|
|
125
125
|
|
|
126
126
|
### Blokery
|
|
127
127
|
|
|
128
|
-
| Bloker
|
|
129
|
-
|
|
128
|
+
| Bloker | Opis | Wymagana akcja |
|
|
129
|
+
| ----------- | ------------- | ----------------- |
|
|
130
130
|
| [Blocker 1] | [Description] | [Required action] |
|
|
131
131
|
|
|
132
132
|
### Analiza problemu
|
|
@@ -201,4 +201,4 @@ Blocker Info: [if blocked]
|
|
|
201
201
|
- [ ] All files listed
|
|
202
202
|
- [ ] Test results included
|
|
203
203
|
- [ ] Angular version noted (14 legacy)
|
|
204
|
-
- [ ] Next steps for non-completed
|
|
204
|
+
- [ ] Next steps for non-completed
|
|
@@ -3,7 +3,7 @@ name: shared-tdd-developer
|
|
|
3
3
|
description: Implement code using strict TDD (Test-Driven Development) methodology for Angular 14 legacy projects. RED → GREEN → REFACTOR cycle is MANDATORY.
|
|
4
4
|
tools: Read, Write, Edit, Glob, Grep, Bash
|
|
5
5
|
model: opus
|
|
6
|
-
color:
|
|
6
|
+
color: '#22C55E'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are a TDD expert implementing code through strict RED → GREEN → REFACTOR cycles.
|
|
@@ -11,6 +11,7 @@ You are a TDD expert implementing code through strict RED → GREEN → REFACTOR
|
|
|
11
11
|
## Primary Responsibility
|
|
12
12
|
|
|
13
13
|
Implement code using Test-Driven Development methodology where:
|
|
14
|
+
|
|
14
15
|
1. **RED**: Write a failing test first
|
|
15
16
|
2. **GREEN**: Write minimal code to pass the test
|
|
16
17
|
3. **REFACTOR**: Improve code while keeping tests green
|
|
@@ -25,13 +26,13 @@ Implement code using Test-Driven Development methodology where:
|
|
|
25
26
|
|
|
26
27
|
**All code MUST use Angular 14 legacy patterns:**
|
|
27
28
|
|
|
28
|
-
| Feature
|
|
29
|
-
|
|
30
|
-
| Control flow
|
|
31
|
-
| DI
|
|
29
|
+
| Feature | ✅ CORRECT | ❌ WRONG |
|
|
30
|
+
| -------------- | ----------------------- | --------------------- |
|
|
31
|
+
| Control flow | `*ngIf`, `*ngFor` | `@if`, `@for` |
|
|
32
|
+
| DI | Constructor injection | `inject()` |
|
|
32
33
|
| Inputs/Outputs | `@Input()`, `@Output()` | `input()`, `output()` |
|
|
33
|
-
| State
|
|
34
|
-
| Derived state
|
|
34
|
+
| State | BehaviorSubject | signals |
|
|
35
|
+
| Derived state | `pipe(map())` | `computed()` |
|
|
35
36
|
|
|
36
37
|
## TDD Cycle
|
|
37
38
|
|
|
@@ -61,6 +62,7 @@ describe('@smartsoft001-mobilems/package-name: FeatureService', () => {
|
|
|
61
62
|
```
|
|
62
63
|
|
|
63
64
|
**Run test and verify it FAILS:**
|
|
65
|
+
|
|
64
66
|
```bash
|
|
65
67
|
nx test <project> --testPathPattern="feature.service.spec.ts"
|
|
66
68
|
```
|
|
@@ -84,6 +86,7 @@ export class FeatureService {
|
|
|
84
86
|
```
|
|
85
87
|
|
|
86
88
|
**Run test and verify it PASSES:**
|
|
89
|
+
|
|
87
90
|
```bash
|
|
88
91
|
nx test <project> --testPathPattern="feature.service.spec.ts"
|
|
89
92
|
```
|
|
@@ -108,6 +111,7 @@ export class FeatureService {
|
|
|
108
111
|
```
|
|
109
112
|
|
|
110
113
|
**Run test and verify it still PASSES:**
|
|
114
|
+
|
|
111
115
|
```bash
|
|
112
116
|
nx test <project> --testPathPattern="feature.service.spec.ts"
|
|
113
117
|
```
|
|
@@ -136,9 +140,7 @@ describe('@smartsoft001-mobilems/package-name: FeatureComponent', () => {
|
|
|
136
140
|
|
|
137
141
|
await TestBed.configureTestingModule({
|
|
138
142
|
declarations: [FeatureComponent], // NOT standalone
|
|
139
|
-
providers: [
|
|
140
|
-
{ provide: FeatureService, useValue: mockService },
|
|
141
|
-
],
|
|
143
|
+
providers: [{ provide: FeatureService, useValue: mockService }],
|
|
142
144
|
schemas: [NO_ERRORS_SCHEMA],
|
|
143
145
|
}).compileComponents();
|
|
144
146
|
|
|
@@ -180,7 +182,7 @@ describe('@smartsoft001-mobilems/package-name: StateService', () => {
|
|
|
180
182
|
});
|
|
181
183
|
|
|
182
184
|
it('should emit initial state', (done) => {
|
|
183
|
-
service.items$.pipe(take(1)).subscribe(items => {
|
|
185
|
+
service.items$.pipe(take(1)).subscribe((items) => {
|
|
184
186
|
expect(items).toEqual([]);
|
|
185
187
|
done();
|
|
186
188
|
});
|
|
@@ -191,7 +193,7 @@ describe('@smartsoft001-mobilems/package-name: StateService', () => {
|
|
|
191
193
|
|
|
192
194
|
service.setItems(newItems);
|
|
193
195
|
|
|
194
|
-
service.items$.pipe(take(1)).subscribe(items => {
|
|
196
|
+
service.items$.pipe(take(1)).subscribe((items) => {
|
|
195
197
|
expect(items).toEqual(newItems);
|
|
196
198
|
done();
|
|
197
199
|
});
|
|
@@ -241,10 +243,9 @@ describe('@smartsoft001-mobilems/package-name: AuthGuard', () => {
|
|
|
241
243
|
const result = guard.canActivate(route, state);
|
|
242
244
|
|
|
243
245
|
(result as any).subscribe((value: any) => {
|
|
244
|
-
expect(mockRouter.createUrlTree).toHaveBeenCalledWith(
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
);
|
|
246
|
+
expect(mockRouter.createUrlTree).toHaveBeenCalledWith(['/login'], {
|
|
247
|
+
queryParams: { returnUrl: '/protected' },
|
|
248
|
+
});
|
|
248
249
|
done();
|
|
249
250
|
});
|
|
250
251
|
});
|
|
@@ -273,6 +274,7 @@ After each cycle, report:
|
|
|
273
274
|
### Phase: REFACTOR 🔄
|
|
274
275
|
|
|
275
276
|
**Changes:**
|
|
277
|
+
|
|
276
278
|
- Added `PricedItem` interface
|
|
277
279
|
- Improved type safety
|
|
278
280
|
|
|
@@ -301,4 +303,4 @@ After each cycle, report:
|
|
|
301
303
|
- [ ] Minimal code to pass (GREEN)
|
|
302
304
|
- [ ] Refactoring done with green tests
|
|
303
305
|
- [ ] Angular 14 patterns used throughout
|
|
304
|
-
- [ ] Coverage meets requirements (90%+)
|
|
306
|
+
- [ ] Coverage meets requirements (90%+)
|
|
@@ -3,7 +3,7 @@ name: shared-ui-classifier
|
|
|
3
3
|
description: Classify whether a task involves UI changes and requires screenshots.
|
|
4
4
|
tools: Read, Glob, Grep
|
|
5
5
|
model: haiku
|
|
6
|
-
color:
|
|
6
|
+
color: '#8B5CF6'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
You are an expert at classifying tasks to determine if they involve UI changes.
|
|
@@ -22,6 +22,7 @@ Analyze implementation plans and determine if the task involves UI changes that
|
|
|
22
22
|
### UI Change: YES
|
|
23
23
|
|
|
24
24
|
Files that indicate UI changes:
|
|
25
|
+
|
|
25
26
|
- `*.component.ts` - Angular components
|
|
26
27
|
- `*.component.html` - Templates
|
|
27
28
|
- `*.component.scss` / `*.component.css` - Styles
|
|
@@ -30,6 +31,7 @@ Files that indicate UI changes:
|
|
|
30
31
|
- Any file in `components/`, `containers/`, `pages/`
|
|
31
32
|
|
|
32
33
|
Keywords that indicate UI changes:
|
|
34
|
+
|
|
33
35
|
- "widok" / "view"
|
|
34
36
|
- "formularz" / "form"
|
|
35
37
|
- "button" / "przycisk"
|
|
@@ -43,6 +45,7 @@ Keywords that indicate UI changes:
|
|
|
43
45
|
### UI Change: NO
|
|
44
46
|
|
|
45
47
|
Files that DON'T indicate UI changes:
|
|
48
|
+
|
|
46
49
|
- `*.service.ts` (services without UI)
|
|
47
50
|
- `*.guard.ts` (route guards)
|
|
48
51
|
- `*.resolver.ts` (route resolvers)
|
|
@@ -53,6 +56,7 @@ Files that DON'T indicate UI changes:
|
|
|
53
56
|
- Configuration files
|
|
54
57
|
|
|
55
58
|
Keywords that indicate NO UI changes:
|
|
59
|
+
|
|
56
60
|
- "backend"
|
|
57
61
|
- "api"
|
|
58
62
|
- "serwis" / "service"
|
|
@@ -70,10 +74,12 @@ Keywords that indicate NO UI changes:
|
|
|
70
74
|
### Analysis
|
|
71
75
|
|
|
72
76
|
**Files to modify:**
|
|
77
|
+
|
|
73
78
|
- `path/to/file1.component.ts` → UI file ✅
|
|
74
79
|
- `path/to/file2.service.ts` → Backend file ❌
|
|
75
80
|
|
|
76
81
|
**Keywords found:**
|
|
82
|
+
|
|
77
83
|
- "formularz" → UI keyword ✅
|
|
78
84
|
|
|
79
85
|
### Decision
|
|
@@ -101,10 +107,12 @@ Or for non-UI changes:
|
|
|
101
107
|
### Analysis
|
|
102
108
|
|
|
103
109
|
**Files to modify:**
|
|
110
|
+
|
|
104
111
|
- `path/to/file1.service.ts` → Backend file ❌
|
|
105
112
|
- `path/to/file2.guard.ts` → Backend file ❌
|
|
106
113
|
|
|
107
114
|
**Keywords found:**
|
|
115
|
+
|
|
108
116
|
- "api" → Backend keyword ❌
|
|
109
117
|
|
|
110
118
|
### Decision
|
|
@@ -134,4 +142,4 @@ Implementation Plan: [files to modify and steps summary]
|
|
|
134
142
|
- [ ] Keywords checked
|
|
135
143
|
- [ ] Clear YES/NO decision
|
|
136
144
|
- [ ] Screenshot plan if YES
|
|
137
|
-
- [ ] Reason documented if NO
|
|
145
|
+
- [ ] Reason documented if NO
|
|
@@ -11,17 +11,17 @@ This skill provides guidance on Angular 14 patterns for legacy projects.
|
|
|
11
11
|
|
|
12
12
|
**DO NOT use modern Angular features (Angular 16+):**
|
|
13
13
|
|
|
14
|
-
| Feature
|
|
15
|
-
|
|
14
|
+
| Feature | CORRECT (Angular 14) | WRONG (Modern) |
|
|
15
|
+
| ------------ | ------------------------------- | ------------------------ |
|
|
16
16
|
| Control flow | `*ngIf`, `*ngFor`, `[ngSwitch]` | `@if`, `@for`, `@switch` |
|
|
17
|
-
| DI
|
|
18
|
-
| Inputs
|
|
19
|
-
| Outputs
|
|
20
|
-
| Two-way
|
|
21
|
-
| State
|
|
22
|
-
| Derived
|
|
23
|
-
| Side effects | `subscribe()`
|
|
24
|
-
| Components
|
|
17
|
+
| DI | Constructor injection | `inject()` |
|
|
18
|
+
| Inputs | `@Input()` decorator | `input()` function |
|
|
19
|
+
| Outputs | `@Output()` decorator | `output()` function |
|
|
20
|
+
| Two-way | `@Input()` + `@Output()` | `model()` |
|
|
21
|
+
| State | BehaviorSubject, Observable | signals, `signal()` |
|
|
22
|
+
| Derived | `pipe(map())` | `computed()` |
|
|
23
|
+
| Side effects | `subscribe()` | `effect()` |
|
|
24
|
+
| Components | NgModule-based | standalone |
|
|
25
25
|
|
|
26
26
|
## 1. Control Flow Syntax (`*ngIf`, `*ngFor`, `[ngSwitch]`)
|
|
27
27
|
|
|
@@ -77,12 +77,12 @@ trackById(index: number, item: Item): string {
|
|
|
77
77
|
|
|
78
78
|
### When to Use
|
|
79
79
|
|
|
80
|
-
| Pattern
|
|
81
|
-
|
|
82
|
-
| `BehaviorSubject`
|
|
83
|
-
| `ReplaySubject(1)` | State without initial value
|
|
84
|
-
| `pipe(map())`
|
|
85
|
-
| `combineLatest`
|
|
80
|
+
| Pattern | Use Case |
|
|
81
|
+
| ------------------ | --------------------------------------- |
|
|
82
|
+
| `BehaviorSubject` | Local, mutable state with initial value |
|
|
83
|
+
| `ReplaySubject(1)` | State without initial value |
|
|
84
|
+
| `pipe(map())` | Derived/computed values |
|
|
85
|
+
| `combineLatest` | Combine multiple observables |
|
|
86
86
|
|
|
87
87
|
### BehaviorSubject Examples
|
|
88
88
|
|
|
@@ -108,13 +108,11 @@ export class StateService {
|
|
|
108
108
|
readonly filtered$ = combineLatest([this._items, this._filter]).pipe(
|
|
109
109
|
map(([items, filter]) => {
|
|
110
110
|
const f = filter.toLowerCase();
|
|
111
|
-
return items.filter(i => i.name.toLowerCase().includes(f));
|
|
112
|
-
})
|
|
111
|
+
return items.filter((i) => i.name.toLowerCase().includes(f));
|
|
112
|
+
}),
|
|
113
113
|
);
|
|
114
114
|
|
|
115
|
-
readonly count$ = this._items.pipe(
|
|
116
|
-
map(items => items.length)
|
|
117
|
-
);
|
|
115
|
+
readonly count$ = this._items.pipe(map((items) => items.length));
|
|
118
116
|
|
|
119
117
|
// Methods to update state
|
|
120
118
|
setItems(items: Item[]): void {
|
|
@@ -158,15 +156,13 @@ export class MyComponent implements OnInit, OnDestroy {
|
|
|
158
156
|
private readonly http: HttpClient,
|
|
159
157
|
private readonly router: Router,
|
|
160
158
|
private readonly myService: MyService,
|
|
161
|
-
@Optional() private readonly optionalService: OptionalService
|
|
159
|
+
@Optional() private readonly optionalService: OptionalService,
|
|
162
160
|
) {}
|
|
163
161
|
|
|
164
162
|
ngOnInit(): void {
|
|
165
|
-
this.myService.items$
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
this.items = items;
|
|
169
|
-
});
|
|
163
|
+
this.myService.items$.pipe(takeUntil(this.destroy$)).subscribe((items) => {
|
|
164
|
+
this.items = items;
|
|
165
|
+
});
|
|
170
166
|
}
|
|
171
167
|
|
|
172
168
|
ngOnDestroy(): void {
|
|
@@ -194,7 +190,7 @@ import {
|
|
|
194
190
|
Output,
|
|
195
191
|
EventEmitter,
|
|
196
192
|
OnChanges,
|
|
197
|
-
SimpleChanges
|
|
193
|
+
SimpleChanges,
|
|
198
194
|
} from '@angular/core';
|
|
199
195
|
|
|
200
196
|
@Component({
|
|
@@ -267,20 +263,9 @@ import { FeatureItemComponent } from './feature-item/feature-item.component';
|
|
|
267
263
|
import { SharedModule } from '@shared/shared.module';
|
|
268
264
|
|
|
269
265
|
@NgModule({
|
|
270
|
-
declarations: [
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
FeatureItemComponent,
|
|
274
|
-
],
|
|
275
|
-
imports: [
|
|
276
|
-
CommonModule,
|
|
277
|
-
FormsModule,
|
|
278
|
-
ReactiveFormsModule,
|
|
279
|
-
SharedModule,
|
|
280
|
-
],
|
|
281
|
-
exports: [
|
|
282
|
-
FeatureComponent,
|
|
283
|
-
],
|
|
266
|
+
declarations: [FeatureComponent, FeatureListComponent, FeatureItemComponent],
|
|
267
|
+
imports: [CommonModule, FormsModule, ReactiveFormsModule, SharedModule],
|
|
268
|
+
exports: [FeatureComponent],
|
|
284
269
|
})
|
|
285
270
|
export class FeatureModule {}
|
|
286
271
|
```
|
|
@@ -358,4 +343,4 @@ export class OptimizedComponent {
|
|
|
358
343
|
- [ ] Using `pipe(map())` for derived state (NOT `computed()`)
|
|
359
344
|
- [ ] Component declared in NgModule (NOT standalone)
|
|
360
345
|
- [ ] Using `async` pipe in templates
|
|
361
|
-
- [ ] Implementing `OnDestroy` with `takeUntil` pattern
|
|
346
|
+
- [ ] Implementing `OnDestroy` with `takeUntil` pattern
|
|
@@ -24,7 +24,7 @@ This skill provides debugging workflows and techniques for Angular 14 legacy pro
|
|
|
24
24
|
```typescript
|
|
25
25
|
@NgModule({
|
|
26
26
|
declarations: [MyComponent], // Is it declared?
|
|
27
|
-
exports: [MyComponent],
|
|
27
|
+
exports: [MyComponent], // Is it exported (if used outside)?
|
|
28
28
|
})
|
|
29
29
|
export class FeatureModule {}
|
|
30
30
|
```
|
|
@@ -68,6 +68,7 @@ This skill provides debugging workflows and techniques for Angular 14 legacy pro
|
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
3. **Memory leak from subscriptions**
|
|
71
|
+
|
|
71
72
|
```typescript
|
|
72
73
|
// Always unsubscribe with takeUntil pattern
|
|
73
74
|
private readonly destroy$ = new Subject<void>();
|
|
@@ -103,7 +104,10 @@ this.cdr.markForCheck();
|
|
|
103
104
|
// HTTP interceptor for logging
|
|
104
105
|
@Injectable()
|
|
105
106
|
export class LoggingInterceptor implements HttpInterceptor {
|
|
106
|
-
intercept(
|
|
107
|
+
intercept(
|
|
108
|
+
req: HttpRequest<any>,
|
|
109
|
+
next: HttpHandler,
|
|
110
|
+
): Observable<HttpEvent<any>> {
|
|
107
111
|
console.log('Request:', req.method, req.url);
|
|
108
112
|
|
|
109
113
|
return next.handle(req).pipe(
|
|
@@ -114,7 +118,7 @@ export class LoggingInterceptor implements HttpInterceptor {
|
|
|
114
118
|
}
|
|
115
119
|
},
|
|
116
120
|
error: (error) => console.error('HTTP Error:', error),
|
|
117
|
-
})
|
|
121
|
+
}),
|
|
118
122
|
);
|
|
119
123
|
}
|
|
120
124
|
}
|
|
@@ -139,9 +143,7 @@ export class AppModule {}
|
|
|
139
143
|
<p>items.length: {{ items?.length }}</p>
|
|
140
144
|
|
|
141
145
|
<!-- Debug *ngFor -->
|
|
142
|
-
<div *ngFor="let item of items; let i = index">
|
|
143
|
-
{{ i }}: {{ item | json }}
|
|
144
|
-
</div>
|
|
146
|
+
<div *ngFor="let item of items; let i = index">{{ i }}: {{ item | json }}</div>
|
|
145
147
|
```
|
|
146
148
|
|
|
147
149
|
### Browser DevTools
|
|
@@ -234,7 +236,9 @@ export class FeatureService {
|
|
|
234
236
|
// Log connection events
|
|
235
237
|
mongoose.connection.on('connected', () => console.log('MongoDB connected'));
|
|
236
238
|
mongoose.connection.on('error', (err) => console.error('MongoDB error:', err));
|
|
237
|
-
mongoose.connection.on('disconnected', () =>
|
|
239
|
+
mongoose.connection.on('disconnected', () =>
|
|
240
|
+
console.log('MongoDB disconnected'),
|
|
241
|
+
);
|
|
238
242
|
```
|
|
239
243
|
|
|
240
244
|
### Query Debugging
|
|
@@ -342,7 +346,11 @@ const name = user?.profile?.name;
|
|
|
342
346
|
const name = user?.profile?.name ?? 'Unknown';
|
|
343
347
|
|
|
344
348
|
// In templates (Angular 14)
|
|
345
|
-
{
|
|
349
|
+
{
|
|
350
|
+
{
|
|
351
|
+
user?.profile?.name;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
346
354
|
```
|
|
347
355
|
|
|
348
356
|
### "Expression has changed after it was checked"
|
|
@@ -384,4 +392,4 @@ export class AppModule {}
|
|
|
384
392
|
providedIn: 'root', // Or specific module
|
|
385
393
|
})
|
|
386
394
|
export class MyService {}
|
|
387
|
-
```
|
|
395
|
+
```
|
|
@@ -9,12 +9,12 @@ This skill provides guidance on Nx 14 monorepo patterns for legacy projects usin
|
|
|
9
9
|
|
|
10
10
|
## CRITICAL: Nx 14 vs Modern Nx
|
|
11
11
|
|
|
12
|
-
| Feature
|
|
13
|
-
|
|
14
|
-
| Packages | `@nrwl/*`
|
|
15
|
-
| Node.js
|
|
16
|
-
| Angular
|
|
17
|
-
| Config
|
|
12
|
+
| Feature | Nx 14 (Legacy) | Nx 21+ (Modern) |
|
|
13
|
+
| -------- | ---------------------------------- | --------------- |
|
|
14
|
+
| Packages | `@nrwl/*` | `@nx/*` |
|
|
15
|
+
| Node.js | 18.x | 20.x / 22.x |
|
|
16
|
+
| Angular | 14.x | 20.x |
|
|
17
|
+
| Config | `workspace.json` or `project.json` | `project.json` |
|
|
18
18
|
|
|
19
19
|
## 1. Workspace Structure
|
|
20
20
|
|
|
@@ -197,10 +197,7 @@ nx affected --target=test --base=main
|
|
|
197
197
|
"lint": {
|
|
198
198
|
"executor": "@nrwl/linter:eslint",
|
|
199
199
|
"options": {
|
|
200
|
-
"lintFilePatterns": [
|
|
201
|
-
"apps/web/src/**/*.ts",
|
|
202
|
-
"apps/web/src/**/*.html"
|
|
203
|
-
]
|
|
200
|
+
"lintFilePatterns": ["apps/web/src/**/*.ts", "apps/web/src/**/*.html"]
|
|
204
201
|
}
|
|
205
202
|
}
|
|
206
203
|
}
|
|
@@ -362,10 +359,10 @@ nx g @nrwl/angular:component my-component --dry-run
|
|
|
362
359
|
|
|
363
360
|
## 13. Package Differences
|
|
364
361
|
|
|
365
|
-
| Feature | @nrwl (Nx 14)
|
|
366
|
-
|
|
367
|
-
| Jest
|
|
368
|
-
| Linter
|
|
369
|
-
| Angular | `@nrwl/angular:*`
|
|
370
|
-
| Node
|
|
371
|
-
| Cypress | `@nrwl/cypress:*`
|
|
362
|
+
| Feature | @nrwl (Nx 14) | @nx (Modern) |
|
|
363
|
+
| ------- | --------------------- | ----------------- |
|
|
364
|
+
| Jest | `@nrwl/jest:jest` | `@nx/jest:jest` |
|
|
365
|
+
| Linter | `@nrwl/linter:eslint` | `@nx/eslint:lint` |
|
|
366
|
+
| Angular | `@nrwl/angular:*` | `@nx/angular:*` |
|
|
367
|
+
| Node | `@nrwl/node:*` | `@nx/node:*` |
|
|
368
|
+
| Cypress | `@nrwl/cypress:*` | `@nx/cypress:*` |
|
|
@@ -143,7 +143,12 @@ describe('@mms/shared-angular: FormFieldComponent', () => {
|
|
|
143
143
|
### Testing with BehaviorSubject State
|
|
144
144
|
|
|
145
145
|
```typescript
|
|
146
|
-
import {
|
|
146
|
+
import {
|
|
147
|
+
ComponentFixture,
|
|
148
|
+
TestBed,
|
|
149
|
+
fakeAsync,
|
|
150
|
+
tick,
|
|
151
|
+
} from '@angular/core/testing';
|
|
147
152
|
import { of, BehaviorSubject } from 'rxjs';
|
|
148
153
|
|
|
149
154
|
import { ListComponent } from './list.component';
|
|
@@ -165,9 +170,7 @@ describe('@mms/shared-angular: ListComponent', () => {
|
|
|
165
170
|
|
|
166
171
|
await TestBed.configureTestingModule({
|
|
167
172
|
declarations: [ListComponent],
|
|
168
|
-
providers: [
|
|
169
|
-
{ provide: StateService, useValue: mockStateService },
|
|
170
|
-
],
|
|
173
|
+
providers: [{ provide: StateService, useValue: mockStateService }],
|
|
171
174
|
}).compileComponents();
|
|
172
175
|
|
|
173
176
|
fixture = TestBed.createComponent(ListComponent);
|
|
@@ -258,7 +261,7 @@ describe('@mms/shared-angular: StateService', () => {
|
|
|
258
261
|
});
|
|
259
262
|
|
|
260
263
|
it('should emit initial state', (done) => {
|
|
261
|
-
service.items$.pipe(take(1)).subscribe(items => {
|
|
264
|
+
service.items$.pipe(take(1)).subscribe((items) => {
|
|
262
265
|
expect(items).toEqual([]);
|
|
263
266
|
done();
|
|
264
267
|
});
|
|
@@ -269,7 +272,7 @@ describe('@mms/shared-angular: StateService', () => {
|
|
|
269
272
|
|
|
270
273
|
service.setItems(newItems);
|
|
271
274
|
|
|
272
|
-
service.items$.pipe(take(1)).subscribe(items => {
|
|
275
|
+
service.items$.pipe(take(1)).subscribe((items) => {
|
|
273
276
|
expect(items).toEqual(newItems);
|
|
274
277
|
done();
|
|
275
278
|
});
|
|
@@ -288,7 +291,10 @@ describe('@mms/shared-angular: StateService', () => {
|
|
|
288
291
|
|
|
289
292
|
```typescript
|
|
290
293
|
import { TestBed } from '@angular/core/testing';
|
|
291
|
-
import {
|
|
294
|
+
import {
|
|
295
|
+
HttpClientTestingModule,
|
|
296
|
+
HttpTestingController,
|
|
297
|
+
} from '@angular/common/http/testing';
|
|
292
298
|
|
|
293
299
|
import { DataService } from './data.service';
|
|
294
300
|
|
|
@@ -491,4 +497,4 @@ nx test shared-angular --testFile=feature.service.spec.ts
|
|
|
491
497
|
6. **Keep tests fast** - avoid real HTTP calls or timers
|
|
492
498
|
7. **Clean up** - use afterEach for cleanup when needed
|
|
493
499
|
8. **Use declarations** - components are NOT standalone in Angular 14
|
|
494
|
-
9. **Mock BehaviorSubjects** - not signals (no signals in Angular 14)
|
|
500
|
+
9. **Mock BehaviorSubjects** - not signals (no signals in Angular 14)
|