@smartsoft001-mobilems/claude-plugins 2.67.0 → 2.69.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.
Files changed (33) hide show
  1. package/.claude-plugin/marketplace.json +4 -0
  2. package/package.json +1 -1
  3. package/plugins/flow/.claude-plugin/plugin.json +1 -1
  4. package/plugins/flow-legacy/.claude-plugin/README.md +143 -0
  5. package/plugins/flow-legacy/.claude-plugin/merge-permissions.js +80 -0
  6. package/plugins/flow-legacy/.claude-plugin/plugin.json +5 -0
  7. package/plugins/flow-legacy/.claude-plugin/settings.template.json +75 -0
  8. package/plugins/flow-legacy/agents/angular-component-scaffolder.md +323 -0
  9. package/plugins/flow-legacy/agents/angular-directive-builder.md +258 -0
  10. package/plugins/flow-legacy/agents/angular-guard-builder.md +322 -0
  11. package/plugins/flow-legacy/agents/angular-pipe-builder.md +227 -0
  12. package/plugins/flow-legacy/agents/angular-resolver-builder.md +332 -0
  13. package/plugins/flow-legacy/agents/angular-service-builder.md +271 -0
  14. package/plugins/flow-legacy/agents/angular-state-builder.md +473 -0
  15. package/plugins/flow-legacy/agents/shared-impl-orchestrator.md +161 -0
  16. package/plugins/flow-legacy/agents/shared-impl-reporter.md +204 -0
  17. package/plugins/flow-legacy/agents/shared-linear-subtask-iterator.md +187 -0
  18. package/plugins/flow-legacy/agents/shared-tdd-developer.md +304 -0
  19. package/plugins/flow-legacy/agents/shared-test-runner.md +131 -0
  20. package/plugins/flow-legacy/agents/shared-ui-classifier.md +137 -0
  21. package/plugins/flow-legacy/commands/commit.md +162 -0
  22. package/plugins/flow-legacy/commands/impl.md +495 -0
  23. package/plugins/flow-legacy/commands/plan.md +488 -0
  24. package/plugins/flow-legacy/commands/push.md +470 -0
  25. package/plugins/flow-legacy/skills/a11y-audit/SKILL.md +214 -0
  26. package/plugins/flow-legacy/skills/angular-patterns/SKILL.md +361 -0
  27. package/plugins/flow-legacy/skills/browser-capture/SKILL.md +238 -0
  28. package/plugins/flow-legacy/skills/debug-helper/SKILL.md +387 -0
  29. package/plugins/flow-legacy/skills/linear-suggestion/SKILL.md +132 -0
  30. package/plugins/flow-legacy/skills/maia-files-delete/SKILL.md +59 -0
  31. package/plugins/flow-legacy/skills/maia-files-upload/SKILL.md +57 -0
  32. package/plugins/flow-legacy/skills/nx-conventions/SKILL.md +371 -0
  33. package/plugins/flow-legacy/skills/test-unit/SKILL.md +494 -0
@@ -0,0 +1,361 @@
1
+ ---
2
+ name: angular-patterns
3
+ description: Angular 14 legacy patterns including *ngIf/*ngFor directives, constructor DI, and @Input/@Output decorators
4
+ ---
5
+
6
+ # Angular 14 Legacy Patterns
7
+
8
+ This skill provides guidance on Angular 14 patterns for legacy projects.
9
+
10
+ ## CRITICAL: Use Legacy Patterns ONLY
11
+
12
+ **DO NOT use modern Angular features (Angular 16+):**
13
+
14
+ | Feature | CORRECT (Angular 14) | WRONG (Modern) |
15
+ |---------|---------------------|----------------|
16
+ | Control flow | `*ngIf`, `*ngFor`, `[ngSwitch]` | `@if`, `@for`, `@switch` |
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
+
26
+ ## 1. Control Flow Syntax (`*ngIf`, `*ngFor`, `[ngSwitch]`)
27
+
28
+ ### Conditional Rendering
29
+
30
+ ```html
31
+ <!-- *ngIf with else -->
32
+ <div *ngIf="isLoading; else loadedContent">
33
+ <app-spinner></app-spinner>
34
+ </div>
35
+ <ng-template #loadedContent>
36
+ <div *ngIf="error; else dataContent">
37
+ <app-error [message]="error?.message"></app-error>
38
+ </div>
39
+ </ng-template>
40
+ <ng-template #dataContent>
41
+ <ul>
42
+ <li *ngFor="let item of items; trackBy: trackById">{{ item.name }}</li>
43
+ </ul>
44
+ <p *ngIf="items.length === 0">No data</p>
45
+ </ng-template>
46
+ ```
47
+
48
+ ### Iteration
49
+
50
+ ```html
51
+ <!-- *ngFor with index and trackBy -->
52
+ <ul>
53
+ <li *ngFor="let item of items; let i = index; trackBy: trackById">
54
+ {{ i + 1 }}. {{ item.name }}
55
+ </li>
56
+ </ul>
57
+ ```
58
+
59
+ ```typescript
60
+ // trackBy function in component
61
+ trackById(index: number, item: Item): string {
62
+ return item.id;
63
+ }
64
+ ```
65
+
66
+ ### Switch Statement
67
+
68
+ ```html
69
+ <div [ngSwitch]="status">
70
+ <span *ngSwitchCase="'pending'" class="text-yellow-500">Pending</span>
71
+ <span *ngSwitchCase="'active'" class="text-green-500">Active</span>
72
+ <span *ngSwitchDefault class="text-gray-500">Unknown</span>
73
+ </div>
74
+ ```
75
+
76
+ ## 2. BehaviorSubject for State Management
77
+
78
+ ### When to Use
79
+
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
+
87
+ ### BehaviorSubject Examples
88
+
89
+ ```typescript
90
+ import { BehaviorSubject } from 'rxjs';
91
+ import { map } from 'rxjs/operators';
92
+
93
+ @Injectable({
94
+ providedIn: 'root',
95
+ })
96
+ export class StateService {
97
+ // Private BehaviorSubject
98
+ private readonly _items = new BehaviorSubject<Item[]>([]);
99
+ private readonly _isLoading = new BehaviorSubject<boolean>(false);
100
+ private readonly _filter = new BehaviorSubject<string>('');
101
+
102
+ // Public Observable (read-only)
103
+ readonly items$ = this._items.asObservable();
104
+ readonly isLoading$ = this._isLoading.asObservable();
105
+ readonly filter$ = this._filter.asObservable();
106
+
107
+ // Derived state using pipe(map())
108
+ readonly filtered$ = combineLatest([this._items, this._filter]).pipe(
109
+ map(([items, filter]) => {
110
+ const f = filter.toLowerCase();
111
+ return items.filter(i => i.name.toLowerCase().includes(f));
112
+ })
113
+ );
114
+
115
+ readonly count$ = this._items.pipe(
116
+ map(items => items.length)
117
+ );
118
+
119
+ // Methods to update state
120
+ setItems(items: Item[]): void {
121
+ this._items.next(items);
122
+ }
123
+
124
+ setLoading(loading: boolean): void {
125
+ this._isLoading.next(loading);
126
+ }
127
+
128
+ setFilter(filter: string): void {
129
+ this._filter.next(filter);
130
+ }
131
+
132
+ // Get current value
133
+ get currentItems(): Item[] {
134
+ return this._items.getValue();
135
+ }
136
+ }
137
+ ```
138
+
139
+ ## 3. Dependency Injection via Constructor
140
+
141
+ ```typescript
142
+ import { Component, OnInit, OnDestroy } from '@angular/core';
143
+ import { Subject } from 'rxjs';
144
+ import { takeUntil } from 'rxjs/operators';
145
+
146
+ @Component({
147
+ selector: 'app-my-component',
148
+ templateUrl: './my-component.component.html',
149
+ styleUrls: ['./my-component.component.scss'],
150
+ })
151
+ export class MyComponent implements OnInit, OnDestroy {
152
+ items: Item[] = [];
153
+
154
+ private readonly destroy$ = new Subject<void>();
155
+
156
+ // Constructor injection (NOT inject())
157
+ constructor(
158
+ private readonly http: HttpClient,
159
+ private readonly router: Router,
160
+ private readonly myService: MyService,
161
+ @Optional() private readonly optionalService: OptionalService
162
+ ) {}
163
+
164
+ ngOnInit(): void {
165
+ this.myService.items$
166
+ .pipe(takeUntil(this.destroy$))
167
+ .subscribe(items => {
168
+ this.items = items;
169
+ });
170
+ }
171
+
172
+ ngOnDestroy(): void {
173
+ this.destroy$.next();
174
+ this.destroy$.complete();
175
+ }
176
+ }
177
+ ```
178
+
179
+ ### Rules
180
+
181
+ - Place dependencies in constructor
182
+ - Use `private readonly` for services
183
+ - Use `@Optional()` for optional dependencies
184
+ - Always implement `OnDestroy` with `takeUntil` pattern
185
+
186
+ ## 4. Input/Output APIs: `@Input()`, `@Output()`, `EventEmitter`
187
+
188
+ ### Decorator Patterns
189
+
190
+ ```typescript
191
+ import {
192
+ Component,
193
+ Input,
194
+ Output,
195
+ EventEmitter,
196
+ OnChanges,
197
+ SimpleChanges
198
+ } from '@angular/core';
199
+
200
+ @Component({
201
+ selector: 'app-form-field',
202
+ templateUrl: './form-field.component.html',
203
+ })
204
+ export class FormFieldComponent implements OnChanges {
205
+ // Required input (validate in ngOnChanges)
206
+ @Input() label!: string;
207
+
208
+ // Optional input with default
209
+ @Input() disabled = false;
210
+
211
+ // Input with setter for transformation
212
+ @Input()
213
+ set count(value: string | number) {
214
+ this._count = typeof value === 'string' ? parseInt(value, 10) : value;
215
+ }
216
+ get count(): number {
217
+ return this._count;
218
+ }
219
+ private _count = 0;
220
+
221
+ // Output event
222
+ @Output() changed = new EventEmitter<string>();
223
+
224
+ // Two-way binding (banana-in-a-box)
225
+ @Input() value = '';
226
+ @Output() valueChange = new EventEmitter<string>();
227
+
228
+ ngOnChanges(changes: SimpleChanges): void {
229
+ if (changes['label'] && !this.label) {
230
+ throw new Error('label is required');
231
+ }
232
+ }
233
+
234
+ onInputChange(newValue: string): void {
235
+ this.value = newValue;
236
+ this.valueChange.emit(newValue);
237
+ this.changed.emit(newValue);
238
+ }
239
+ }
240
+ ```
241
+
242
+ ### Usage in Templates
243
+
244
+ ```html
245
+ <!-- Parent template -->
246
+ <app-form-field
247
+ label="Name"
248
+ [disabled]="isDisabled"
249
+ [(value)]="name"
250
+ (changed)="onChanged($event)"
251
+ ></app-form-field>
252
+ ```
253
+
254
+ ## 5. NgModule-based Components
255
+
256
+ All components must be declared in a module:
257
+
258
+ ```typescript
259
+ // feature.module.ts
260
+ import { NgModule } from '@angular/core';
261
+ import { CommonModule } from '@angular/common';
262
+ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
263
+
264
+ import { FeatureComponent } from './feature.component';
265
+ import { FeatureListComponent } from './feature-list/feature-list.component';
266
+ import { FeatureItemComponent } from './feature-item/feature-item.component';
267
+ import { SharedModule } from '@shared/shared.module';
268
+
269
+ @NgModule({
270
+ declarations: [
271
+ FeatureComponent,
272
+ FeatureListComponent,
273
+ FeatureItemComponent,
274
+ ],
275
+ imports: [
276
+ CommonModule,
277
+ FormsModule,
278
+ ReactiveFormsModule,
279
+ SharedModule,
280
+ ],
281
+ exports: [
282
+ FeatureComponent,
283
+ ],
284
+ })
285
+ export class FeatureModule {}
286
+ ```
287
+
288
+ ```typescript
289
+ // feature.component.ts
290
+ @Component({
291
+ selector: 'app-feature',
292
+ templateUrl: './feature.component.html',
293
+ styleUrls: ['./feature.component.scss'],
294
+ })
295
+ export class FeatureComponent implements OnInit, OnDestroy {
296
+ // ... component logic
297
+ }
298
+ ```
299
+
300
+ ## 6. Async Pipe Usage
301
+
302
+ Always prefer `async` pipe over manual subscriptions in templates:
303
+
304
+ ```html
305
+ <!-- Using async pipe -->
306
+ <div *ngIf="isLoading$ | async; else content">
307
+ <app-spinner></app-spinner>
308
+ </div>
309
+ <ng-template #content>
310
+ <ul>
311
+ <li *ngFor="let item of items$ | async; trackBy: trackById">
312
+ {{ item.name }}
313
+ </li>
314
+ </ul>
315
+ </ng-template>
316
+ ```
317
+
318
+ ```typescript
319
+ @Component({...})
320
+ export class ListComponent {
321
+ readonly isLoading$ = this.stateService.isLoading$;
322
+ readonly items$ = this.stateService.items$;
323
+
324
+ constructor(private readonly stateService: StateService) {}
325
+
326
+ trackById(index: number, item: Item): string {
327
+ return item.id;
328
+ }
329
+ }
330
+ ```
331
+
332
+ ## 7. Performance Guidelines
333
+
334
+ - Every `*ngFor` must have a `trackBy` function
335
+ - Extract complex logic from templates to component methods
336
+ - Use `OnPush` change detection when appropriate
337
+ - Avoid function calls in templates (use getters or properties)
338
+
339
+ ```typescript
340
+ @Component({
341
+ selector: 'app-optimized',
342
+ templateUrl: './optimized.component.html',
343
+ changeDetection: ChangeDetectionStrategy.OnPush,
344
+ })
345
+ export class OptimizedComponent {
346
+ // ...
347
+ }
348
+ ```
349
+
350
+ ## 8. PR Checklist (Angular 14 Legacy)
351
+
352
+ - [ ] Using `*ngIf`/`*ngFor` (NOT `@if`/`@for`)
353
+ - [ ] Using `[ngSwitch]` (NOT `@switch`)
354
+ - [ ] Every `*ngFor` has `trackBy` function
355
+ - [ ] Using constructor DI (NOT `inject()`)
356
+ - [ ] Using `@Input()`/`@Output()` decorators (NOT `input()`/`output()`)
357
+ - [ ] Using BehaviorSubject for state (NOT signals)
358
+ - [ ] Using `pipe(map())` for derived state (NOT `computed()`)
359
+ - [ ] Component declared in NgModule (NOT standalone)
360
+ - [ ] Using `async` pipe in templates
361
+ - [ ] Implementing `OnDestroy` with `takeUntil` pattern
@@ -0,0 +1,238 @@
1
+ ---
2
+ name: browser-capture
3
+ description: Manage browser sessions and capture screenshots. Ensures dev server is running, navigates to pages, captures responsive screenshots, and uploads them to temporary storage.
4
+ allowed-tools:
5
+ - Bash
6
+ - Read
7
+ - Glob
8
+ - mcp__playwright__browser_navigate
9
+ - mcp__playwright__browser_snapshot
10
+ - mcp__playwright__browser_take_screenshot
11
+ - mcp__playwright__browser_resize
12
+ - mcp__playwright__browser_close
13
+ ---
14
+
15
+ # Browser Capture Skill
16
+
17
+ Manage browser sessions for capturing screenshots of web pages. Automatically ensures the development server is running before capturing.
18
+
19
+ ## Capabilities
20
+
21
+ 1. **Server Management**: Check if dev server is running, start if needed
22
+ 2. **Page Navigation**: Navigate to specified URLs using Playwright
23
+ 3. **Screenshot Capture**: Take screenshots at multiple viewport sizes
24
+ 4. **Upload Screenshots**: Upload captured images to maia-api for use in reports
25
+
26
+ ## Server Management
27
+
28
+ ### Read Port Configuration
29
+
30
+ ```bash
31
+ # Default port location (Nx 14 / Angular 14)
32
+ grep -o '"port":[^,}]*' apps/web/project.json | head -1
33
+ # Default: 4200
34
+ ```
35
+
36
+ ### Check if Server is Running
37
+
38
+ ```bash
39
+ lsof -i :4200 -t
40
+ ```
41
+
42
+ - If returns PID -> server is running
43
+ - If returns nothing -> server needs to be started
44
+
45
+ ### Start Server if Needed
46
+
47
+ ```bash
48
+ # Start in background (Nx 14 / @nrwl)
49
+ npm start &
50
+
51
+ # Wait for server to be ready (check every 2 seconds, max 30 seconds)
52
+ for i in {1..15}; do
53
+ curl -s http://localhost:4200 > /dev/null && break
54
+ sleep 2
55
+ done
56
+ ```
57
+
58
+ ## Screenshot Capture Process
59
+
60
+ ### 1. Ensure Server is Running
61
+
62
+ Before any screenshot capture:
63
+
64
+ 1. Read port from `apps/web/project.json` (default: 4200)
65
+ 2. Check if port is occupied: `lsof -i :PORT -t`
66
+ 3. If not running: `npm start &` and wait ~15 seconds
67
+
68
+ ### 2. Navigate to Page
69
+
70
+ Use `mcp__playwright__browser_navigate` to open the target URL.
71
+
72
+ ```
73
+ URL format: http://localhost:{port}/{path}
74
+ ```
75
+
76
+ ### 3. Capture at Multiple Viewports
77
+
78
+ Standard viewport sizes:
79
+
80
+ | Name | Width | Height |
81
+ | ------- | ----- | ------ |
82
+ | Desktop | 1920 | 1080 |
83
+ | Tablet | 768 | 1024 |
84
+ | Mobile | 375 | 667 |
85
+
86
+ Process for each viewport:
87
+
88
+ 1. `mcp__playwright__browser_resize` -> set dimensions
89
+ 2. `mcp__playwright__browser_take_screenshot` -> save to temp file
90
+
91
+ ### 4. Upload Screenshots
92
+
93
+ After capturing, delegate upload to `maia-api` agent:
94
+
95
+ ```
96
+ Input: /tmp/screenshot-desktop.png
97
+ Output: { id: "abc123", url: "https://maia-ai-api.smartsoft.biz.pl/files/abc123" }
98
+ ```
99
+
100
+ ## Usage Examples
101
+
102
+ ### Capture Single Page
103
+
104
+ ```
105
+ Input: { path: "/articles", viewports: ["desktop", "mobile"] }
106
+
107
+ Process:
108
+ 1. Check server running on port 4200
109
+ 2. Start if needed, wait for ready
110
+ 3. Navigate to http://localhost:4200/articles
111
+ 4. Resize to 1920x1080, screenshot -> /tmp/articles-desktop.png
112
+ 5. Resize to 375x667, screenshot -> /tmp/articles-mobile.png
113
+ 6. Upload both via maia-api agent
114
+ 7. Return URLs
115
+
116
+ Output:
117
+ {
118
+ "desktop": "https://maia-ai-api.smartsoft.biz.pl/files/abc123",
119
+ "mobile": "https://maia-ai-api.smartsoft.biz.pl/files/def456"
120
+ }
121
+ ```
122
+
123
+ ### Capture Before/After
124
+
125
+ ```
126
+ Input: {
127
+ path: "/profile",
128
+ phase: "before" | "after",
129
+ viewports: ["desktop", "mobile"]
130
+ }
131
+
132
+ Output:
133
+ {
134
+ "phase": "before",
135
+ "desktop": { "id": "abc123", "url": "https://..." },
136
+ "mobile": { "id": "def456", "url": "https://..." }
137
+ }
138
+ ```
139
+
140
+ ## Viewport Presets
141
+
142
+ | Preset | Dimensions | Use Case |
143
+ | ---------- | ---------- | ------------------------ |
144
+ | `desktop` | 1920x1080 | Full desktop view |
145
+ | `laptop` | 1366x768 | Common laptop resolution |
146
+ | `tablet` | 768x1024 | iPad portrait |
147
+ | `mobile` | 375x667 | iPhone SE/8 |
148
+ | `mobile-l` | 414x896 | iPhone XR/11 |
149
+
150
+ ## Server Ready Check
151
+
152
+ ```bash
153
+ # Check if server responds
154
+ check_server() {
155
+ local port=$1
156
+ local max_attempts=$2
157
+ local attempt=1
158
+
159
+ while [ $attempt -le $max_attempts ]; do
160
+ if curl -s "http://localhost:$port" > /dev/null 2>&1; then
161
+ echo "Server ready"
162
+ return 0
163
+ fi
164
+ echo "Waiting for server... ($attempt/$max_attempts)"
165
+ sleep 2
166
+ ((attempt++))
167
+ done
168
+
169
+ echo "Server not ready after $max_attempts attempts"
170
+ return 1
171
+ }
172
+
173
+ check_server 4200 15
174
+ ```
175
+
176
+ ## Output Format
177
+
178
+ When capturing screenshots, return structured data:
179
+
180
+ ```json
181
+ {
182
+ "serverStarted": true,
183
+ "port": 4200,
184
+ "screenshots": [
185
+ {
186
+ "viewport": "desktop",
187
+ "dimensions": "1920x1080",
188
+ "localPath": "/tmp/screenshot-desktop.png",
189
+ "uploadedId": "abc123",
190
+ "uploadedUrl": "https://maia-ai-api.smartsoft.biz.pl/files/abc123"
191
+ },
192
+ {
193
+ "viewport": "mobile",
194
+ "dimensions": "375x667",
195
+ "localPath": "/tmp/screenshot-mobile.png",
196
+ "uploadedId": "def456",
197
+ "uploadedUrl": "https://maia-ai-api.smartsoft.biz.pl/files/def456"
198
+ }
199
+ ]
200
+ }
201
+ ```
202
+
203
+ ## Cleanup
204
+
205
+ After screenshots are used (embedded in Linear comments), cleanup local temp files:
206
+
207
+ ```bash
208
+ rm /tmp/screenshot-*.png
209
+ ```
210
+
211
+ For API cleanup, delegate to `maia-api` agent with collected IDs.
212
+
213
+ ## Error Handling
214
+
215
+ ### Server Won't Start
216
+
217
+ If server fails to start after 30 seconds:
218
+
219
+ 1. Check for port conflicts: `lsof -i :4200`
220
+ 2. Check npm logs for errors
221
+ 3. Report error and skip screenshot capture
222
+
223
+ ### Screenshot Fails
224
+
225
+ If Playwright screenshot fails:
226
+
227
+ 1. Verify navigation succeeded
228
+ 2. Check for JavaScript errors: `mcp__playwright__browser_console_messages`
229
+ 3. Try alternative viewport
230
+ 4. Report partial success
231
+
232
+ ### Upload Fails
233
+
234
+ If maia-api upload fails:
235
+
236
+ 1. Verify file exists and has content
237
+ 2. Retry upload once
238
+ 3. Report error with local file path as fallback