@smartsoft001-mobilems/claude-plugins 2.58.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/.claude-plugin/marketplace.json +14 -0
- package/package.json +13 -0
- package/plugins/flow/.claude-plugin/plugin.json +5 -0
- package/plugins/flow/agents/angular-component-scaffolder.md +174 -0
- package/plugins/flow/agents/angular-directive-builder.md +152 -0
- package/plugins/flow/agents/angular-guard-builder.md +242 -0
- package/plugins/flow/agents/angular-jest-test-writer.md +473 -0
- package/plugins/flow/agents/angular-pipe-builder.md +168 -0
- package/plugins/flow/agents/angular-resolver-builder.md +285 -0
- package/plugins/flow/agents/angular-service-builder.md +160 -0
- package/plugins/flow/agents/angular-signal-state-builder.md +338 -0
- package/plugins/flow/agents/angular-test-diagnostician.md +278 -0
- package/plugins/flow/agents/angular-testbed-configurator.md +314 -0
- package/plugins/flow/agents/arch-scaffolder.md +277 -0
- package/plugins/flow/agents/shared-build-verifier.md +159 -0
- package/plugins/flow/agents/shared-config-updater.md +309 -0
- package/plugins/flow/agents/shared-coverage-enforcer.md +183 -0
- package/plugins/flow/agents/shared-error-handler.md +216 -0
- package/plugins/flow/agents/shared-file-creator.md +343 -0
- package/plugins/flow/agents/shared-impl-orchestrator.md +309 -0
- package/plugins/flow/agents/shared-impl-reporter.md +338 -0
- package/plugins/flow/agents/shared-linear-subtask-iterator.md +336 -0
- package/plugins/flow/agents/shared-logic-implementer.md +242 -0
- package/plugins/flow/agents/shared-maia-api.md +25 -0
- package/plugins/flow/agents/shared-performance-validator.md +167 -0
- package/plugins/flow/agents/shared-project-standardizer.md +204 -0
- package/plugins/flow/agents/shared-security-scanner.md +185 -0
- package/plugins/flow/agents/shared-style-enforcer.md +229 -0
- package/plugins/flow/agents/shared-tdd-developer.md +349 -0
- package/plugins/flow/agents/shared-test-fixer.md +185 -0
- package/plugins/flow/agents/shared-test-runner.md +190 -0
- package/plugins/flow/agents/shared-ui-classifier.md +229 -0
- package/plugins/flow/agents/shared-verification-orchestrator.md +193 -0
- package/plugins/flow/agents/shared-verification-runner.md +139 -0
- package/plugins/flow/agents/ui-a11y-validator.md +304 -0
- package/plugins/flow/agents/ui-screenshot-reporter.md +328 -0
- package/plugins/flow/agents/ui-web-designer.md +213 -0
- package/plugins/flow/commands/commit.md +131 -0
- package/plugins/flow/commands/impl.md +625 -0
- package/plugins/flow/commands/plan.md +598 -0
- package/plugins/flow/commands/push.md +584 -0
- package/plugins/flow/skills/a11y-audit/SKILL.md +214 -0
- package/plugins/flow/skills/angular-patterns/SKILL.md +191 -0
- package/plugins/flow/skills/browser-capture/SKILL.md +238 -0
- package/plugins/flow/skills/debug-helper/SKILL.md +375 -0
- package/plugins/flow/skills/maia-files-delete/SKILL.md +60 -0
- package/plugins/flow/skills/maia-files-upload/SKILL.md +58 -0
- package/plugins/flow/skills/nx-conventions/SKILL.md +327 -0
- package/plugins/flow/skills/test-unit/SKILL.md +456 -0
- package/src/index.d.ts +6 -0
- package/src/index.js +10 -0
- package/src/index.js.map +1 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: a11y-audit
|
|
3
|
+
description: Run accessibility audits on web pages. Ensures dev server is running, navigates to pages, captures accessibility snapshots, and runs axe-core tests.
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Bash
|
|
6
|
+
- Read
|
|
7
|
+
- Glob
|
|
8
|
+
- mcp__playwright__browser_navigate
|
|
9
|
+
- mcp__playwright__browser_snapshot
|
|
10
|
+
- mcp__playwright__browser_evaluate
|
|
11
|
+
- mcp__playwright__browser_close
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Accessibility Audit Skill
|
|
15
|
+
|
|
16
|
+
Run accessibility audits on web pages using Playwright and axe-core. Automatically ensures the development server is running before auditing.
|
|
17
|
+
|
|
18
|
+
## Capabilities
|
|
19
|
+
|
|
20
|
+
1. **Server Management**: Check if dev server is running, start if needed
|
|
21
|
+
2. **Page Navigation**: Navigate to specified URLs using Playwright
|
|
22
|
+
3. **Accessibility Snapshot**: Capture accessibility tree for analysis
|
|
23
|
+
4. **Axe-core Testing**: Run automated accessibility tests
|
|
24
|
+
|
|
25
|
+
## Server Management
|
|
26
|
+
|
|
27
|
+
### Read Port Configuration
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Default port location
|
|
31
|
+
grep -o '"port":[^,}]*' apps/web/project.json | head -1
|
|
32
|
+
# Default: 4210
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Check if Server is Running
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
lsof -i :4210 -t
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- If returns PID → server is running
|
|
42
|
+
- If returns nothing → server needs to be started
|
|
43
|
+
|
|
44
|
+
### Start Server if Needed
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Start in background
|
|
48
|
+
npm start &
|
|
49
|
+
|
|
50
|
+
# Wait for server to be ready
|
|
51
|
+
for i in {1..15}; do
|
|
52
|
+
curl -s http://localhost:4210 > /dev/null && break
|
|
53
|
+
sleep 2
|
|
54
|
+
done
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Audit Process
|
|
58
|
+
|
|
59
|
+
### 1. Ensure Server is Running
|
|
60
|
+
|
|
61
|
+
Before any audit:
|
|
62
|
+
|
|
63
|
+
1. Read port from `apps/web/project.json` (default: 4210)
|
|
64
|
+
2. Check if port is occupied: `lsof -i :PORT -t`
|
|
65
|
+
3. If not running: `npm start &` and wait ~15 seconds
|
|
66
|
+
|
|
67
|
+
### 2. Navigate to Page
|
|
68
|
+
|
|
69
|
+
Use `mcp__playwright__browser_navigate` to open the target URL.
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
URL format: http://localhost:{port}/{path}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 3. Capture Accessibility Snapshot
|
|
76
|
+
|
|
77
|
+
Use `mcp__playwright__browser_snapshot` to get the accessibility tree.
|
|
78
|
+
|
|
79
|
+
This provides:
|
|
80
|
+
|
|
81
|
+
- Element roles and names
|
|
82
|
+
- ARIA attributes
|
|
83
|
+
- Focus states
|
|
84
|
+
- Interactive element information
|
|
85
|
+
|
|
86
|
+
### 4. Run Axe-core Audit
|
|
87
|
+
|
|
88
|
+
Use `mcp__playwright__browser_evaluate` to inject and run axe-core:
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
// Example evaluation code
|
|
92
|
+
async () => {
|
|
93
|
+
// Load axe-core from CDN
|
|
94
|
+
const script = document.createElement('script');
|
|
95
|
+
script.src =
|
|
96
|
+
'https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.8.2/axe.min.js';
|
|
97
|
+
document.head.appendChild(script);
|
|
98
|
+
|
|
99
|
+
await new Promise((resolve) => (script.onload = resolve));
|
|
100
|
+
|
|
101
|
+
// Run audit
|
|
102
|
+
const results = await axe.run();
|
|
103
|
+
return {
|
|
104
|
+
violations: results.violations,
|
|
105
|
+
passes: results.passes.length,
|
|
106
|
+
incomplete: results.incomplete,
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Usage Examples
|
|
112
|
+
|
|
113
|
+
### Full Page Audit
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
Input: { path: "/articles" }
|
|
117
|
+
|
|
118
|
+
Process:
|
|
119
|
+
1. Check server running on port 4210
|
|
120
|
+
2. Start if needed, wait for ready
|
|
121
|
+
3. Navigate to http://localhost:4210/articles
|
|
122
|
+
4. Capture accessibility snapshot
|
|
123
|
+
5. Run axe-core audit
|
|
124
|
+
6. Return violations and recommendations
|
|
125
|
+
|
|
126
|
+
Output:
|
|
127
|
+
{
|
|
128
|
+
"url": "http://localhost:4210/articles",
|
|
129
|
+
"snapshot": { ... accessibility tree ... },
|
|
130
|
+
"violations": [
|
|
131
|
+
{
|
|
132
|
+
"id": "image-alt",
|
|
133
|
+
"impact": "critical",
|
|
134
|
+
"description": "Images must have alternate text",
|
|
135
|
+
"nodes": [...]
|
|
136
|
+
}
|
|
137
|
+
],
|
|
138
|
+
"passes": 45,
|
|
139
|
+
"incomplete": 2
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Quick Check
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
Input: { path: "/", snapshotOnly: true }
|
|
147
|
+
|
|
148
|
+
Output:
|
|
149
|
+
{
|
|
150
|
+
"url": "http://localhost:4210/",
|
|
151
|
+
"snapshot": { ... accessibility tree ... }
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Report Format
|
|
156
|
+
|
|
157
|
+
When generating reports, use this structure:
|
|
158
|
+
|
|
159
|
+
```markdown
|
|
160
|
+
## Accessibility Audit Report
|
|
161
|
+
|
|
162
|
+
**Page**: [URL]
|
|
163
|
+
**Date**: [Date]
|
|
164
|
+
**Standard**: WCAG 2.1 Level AA
|
|
165
|
+
|
|
166
|
+
### Critical Issues (Must Fix)
|
|
167
|
+
|
|
168
|
+
| Issue | Elements | WCAG | Fix |
|
|
169
|
+
| ----------- | -------- | ----- | ------------------------ |
|
|
170
|
+
| Missing alt | 3 images | 1.1.1 | Add descriptive alt text |
|
|
171
|
+
|
|
172
|
+
### Serious Issues (Should Fix)
|
|
173
|
+
|
|
174
|
+
| Issue | Elements | WCAG | Fix |
|
|
175
|
+
| ------------ | ---------- | ----- | ---------------- |
|
|
176
|
+
| Low contrast | 2 elements | 1.4.3 | Use darker color |
|
|
177
|
+
|
|
178
|
+
### Passed Checks
|
|
179
|
+
|
|
180
|
+
- [x] Page has lang attribute
|
|
181
|
+
- [x] Headings in correct order
|
|
182
|
+
- [x] Form inputs have labels
|
|
183
|
+
|
|
184
|
+
### Summary
|
|
185
|
+
|
|
186
|
+
- Violations: X critical, Y serious, Z minor
|
|
187
|
+
- Passed: N checks
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Error Handling
|
|
191
|
+
|
|
192
|
+
### Server Won't Start
|
|
193
|
+
|
|
194
|
+
If server fails to start after 30 seconds:
|
|
195
|
+
|
|
196
|
+
1. Check for port conflicts
|
|
197
|
+
2. Check npm logs for errors
|
|
198
|
+
3. Report error and skip audit
|
|
199
|
+
|
|
200
|
+
### Axe-core Load Fails
|
|
201
|
+
|
|
202
|
+
If axe-core fails to load:
|
|
203
|
+
|
|
204
|
+
1. Check network connectivity
|
|
205
|
+
2. Try alternative CDN
|
|
206
|
+
3. Fall back to snapshot-only audit
|
|
207
|
+
|
|
208
|
+
### Navigation Fails
|
|
209
|
+
|
|
210
|
+
If page doesn't load:
|
|
211
|
+
|
|
212
|
+
1. Verify URL is correct
|
|
213
|
+
2. Check for JavaScript errors
|
|
214
|
+
3. Report partial results
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: angular-patterns
|
|
3
|
+
description: Angular 20 modern patterns including signals, standalone components, and new control flow syntax
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Angular 20 Modern Patterns
|
|
7
|
+
|
|
8
|
+
This skill provides guidance on Angular 20 best practices for this project.
|
|
9
|
+
|
|
10
|
+
## 1. Control Flow Syntax (`@if`, `@for`, `@switch`)
|
|
11
|
+
|
|
12
|
+
- Prefer `@if` over `*ngIf` and `@switch` over `ngSwitch`
|
|
13
|
+
- Prefer `@for` over `*ngFor`; always provide an explicit `track` expression
|
|
14
|
+
- Do not mix old and new syntax in the same file
|
|
15
|
+
|
|
16
|
+
### Examples
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
@if (isLoading()) {
|
|
20
|
+
<app-spinner />
|
|
21
|
+
} @else if (error()) {
|
|
22
|
+
<app-error [message]="error()?.message" />
|
|
23
|
+
} @else {
|
|
24
|
+
<ul>
|
|
25
|
+
@for (item of items(); track item.id) {
|
|
26
|
+
<li>{{ item.name }}</li>
|
|
27
|
+
} @empty {
|
|
28
|
+
<li>No data</li>
|
|
29
|
+
}
|
|
30
|
+
</ul>
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
@switch (status()) { @case ('pending') {
|
|
36
|
+
<span class="smart-text-yellow-500">Pending</span>
|
|
37
|
+
} @case ('active') {
|
|
38
|
+
<span class="smart-text-green-500">Active</span>
|
|
39
|
+
} @default {
|
|
40
|
+
<span class="smart-text-gray-500">Unknown</span>
|
|
41
|
+
} }
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 2. Signals
|
|
45
|
+
|
|
46
|
+
### When to Use
|
|
47
|
+
|
|
48
|
+
| Pattern | Use Case |
|
|
49
|
+
| ------------ | ---------------------------------------------------- |
|
|
50
|
+
| `signal()` | Local, mutable component state |
|
|
51
|
+
| `computed()` | Pure derivations from other signals |
|
|
52
|
+
| `effect()` | Side-effects (logging, syncing, service interaction) |
|
|
53
|
+
| `toSignal()` | Convert Observable to Signal |
|
|
54
|
+
|
|
55
|
+
### Signal Examples
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// Local state
|
|
59
|
+
readonly items = signal<Item[]>([]);
|
|
60
|
+
readonly isLoading = signal(false);
|
|
61
|
+
|
|
62
|
+
// Computed derivation
|
|
63
|
+
readonly filtered = computed(() => {
|
|
64
|
+
const f = this.filter().toLowerCase();
|
|
65
|
+
return this.items().filter(i => i.name.toLowerCase().includes(f));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Effect for side-effects only
|
|
69
|
+
private readonly syncEffect = effect(() => {
|
|
70
|
+
const items = this.items();
|
|
71
|
+
this.analyticsService.track('items-loaded', { count: items.length });
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### RxJS Bridging
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// Observable → Signal
|
|
79
|
+
private readonly data$ = this.http.get<Data[]>('/api/data');
|
|
80
|
+
readonly data = toSignal(this.data$, { initialValue: [] });
|
|
81
|
+
|
|
82
|
+
// Signal → Observable (only when needed)
|
|
83
|
+
readonly filter$ = toObservable(this.filter);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Naming Conventions
|
|
87
|
+
|
|
88
|
+
- No `Signal`/`Sig` suffix—use semantic names (`items`, `isLoading`)
|
|
89
|
+
- Use descriptive names: `selectedItem`, `filteredResults`, `hasError`
|
|
90
|
+
|
|
91
|
+
## 3. Dependency Injection via `inject()`
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
@Component({...})
|
|
95
|
+
export class MyComponent {
|
|
96
|
+
// Standard pattern
|
|
97
|
+
private readonly http = inject(HttpClient);
|
|
98
|
+
private readonly router = inject(Router);
|
|
99
|
+
private readonly myService = inject(MyService);
|
|
100
|
+
|
|
101
|
+
// Optional dependency
|
|
102
|
+
private readonly optionalService = inject(OptionalService, { optional: true });
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Rules
|
|
107
|
+
|
|
108
|
+
- Place `inject()` calls near the top of the class
|
|
109
|
+
- Never call `inject()` inside loops or event handlers
|
|
110
|
+
- Assign to `readonly` properties
|
|
111
|
+
|
|
112
|
+
## 4. Input/Output APIs: `input()`, `output()`, `model()`
|
|
113
|
+
|
|
114
|
+
### New API Patterns
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
@Component({...})
|
|
118
|
+
export class FormFieldComponent {
|
|
119
|
+
// Required input
|
|
120
|
+
readonly label = input.required<string>();
|
|
121
|
+
|
|
122
|
+
// Optional input with default
|
|
123
|
+
readonly disabled = input(false);
|
|
124
|
+
|
|
125
|
+
// Input with transform
|
|
126
|
+
readonly count = input<number, string>(0, {
|
|
127
|
+
transform: (v) => parseInt(v, 10)
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Output event
|
|
131
|
+
readonly changed = output<string>();
|
|
132
|
+
|
|
133
|
+
// Two-way binding (use sparingly)
|
|
134
|
+
readonly value = model<string>('');
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Usage in Templates
|
|
139
|
+
|
|
140
|
+
```html
|
|
141
|
+
<!-- Parent template -->
|
|
142
|
+
<app-form-field
|
|
143
|
+
label="Name"
|
|
144
|
+
[disabled]="isDisabled()"
|
|
145
|
+
[(value)]="name"
|
|
146
|
+
(changed)="onChanged($event)"
|
|
147
|
+
/>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## 5. Standalone Components
|
|
151
|
+
|
|
152
|
+
All new components should be standalone:
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
@Component({
|
|
156
|
+
selector: 'app-feature',
|
|
157
|
+
standalone: true,
|
|
158
|
+
imports: [CommonModule, RouterModule, SharedModule],
|
|
159
|
+
template: `...`,
|
|
160
|
+
styles: `...`,
|
|
161
|
+
})
|
|
162
|
+
export class FeatureComponent {
|
|
163
|
+
// ...
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## 6. Performance Guidelines
|
|
168
|
+
|
|
169
|
+
- Every `@for` must have a stable `track` expression (prefer `item.id` over index)
|
|
170
|
+
- Extract complex conditions into `computed()` signals
|
|
171
|
+
- Avoid allocating new arrays/objects in template expressions
|
|
172
|
+
- Use `OnPush` change detection when appropriate
|
|
173
|
+
|
|
174
|
+
## 7. Migration Order (Legacy Code)
|
|
175
|
+
|
|
176
|
+
When touching legacy code, migrate in this order:
|
|
177
|
+
|
|
178
|
+
1. `*ngIf` → `@if`
|
|
179
|
+
2. `*ngFor` → `@for` (add `track`)
|
|
180
|
+
3. Constructor DI → `inject()`
|
|
181
|
+
4. `@Input/@Output` → `input()/output()/model()`
|
|
182
|
+
5. Simple state Observables → signals
|
|
183
|
+
|
|
184
|
+
## 8. PR Checklist
|
|
185
|
+
|
|
186
|
+
- [ ] No mixing of `*ngIf/*ngFor` with `@if/@for` in same logical block
|
|
187
|
+
- [ ] Every `@for` has a `track` expression
|
|
188
|
+
- [ ] No unnecessary `subscribe()` calls (use `toSignal`)
|
|
189
|
+
- [ ] DI uses `inject()` (no new constructor-based DI)
|
|
190
|
+
- [ ] Inputs/Outputs use `input()/output()/model()` in new code
|
|
191
|
+
- [ ] No heavy inline computations in templates
|
|
@@ -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
|
|
32
|
+
grep -o '"port":[^,}]*' apps/web/project.json | head -1
|
|
33
|
+
# Default: 4210
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Check if Server is Running
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
lsof -i :4210 -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
|
|
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:4210 > /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: 4210)
|
|
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 4210
|
|
109
|
+
2. Start if needed, wait for ready
|
|
110
|
+
3. Navigate to http://localhost:4210/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 4210 15
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Output Format
|
|
177
|
+
|
|
178
|
+
When capturing screenshots, return structured data:
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"serverStarted": true,
|
|
183
|
+
"port": 4210,
|
|
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 :4210`
|
|
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
|