ima-claude 2.18.0 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -9
- package/dist/cli.js +5 -1
- package/package.json +1 -1
- package/plugins/ima-claude/.claude-plugin/plugin.json +2 -2
- package/plugins/ima-claude/agents/explorer.md +29 -15
- package/plugins/ima-claude/agents/implementer.md +58 -13
- package/plugins/ima-claude/agents/memory.md +19 -19
- package/plugins/ima-claude/agents/reviewer.md +56 -34
- package/plugins/ima-claude/agents/tester.md +59 -16
- package/plugins/ima-claude/agents/wp-developer.md +66 -21
- package/plugins/ima-claude/hooks/bootstrap.sh +42 -44
- package/plugins/ima-claude/hooks/prompt_coach_digest.md +14 -17
- package/plugins/ima-claude/hooks/prompt_coach_system.md +10 -12
- package/plugins/ima-claude/personalities/README.md +17 -6
- package/plugins/ima-claude/personalities/enable-efficient.md +61 -0
- package/plugins/ima-claude/personalities/enable-terse.md +71 -0
- package/plugins/ima-claude/skills/agentic-workflows/SKILL.md +97 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/phases/deliver.md +181 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/phases/draft.md +99 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/phases/gather.md +130 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/phases/outline.md +106 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/phases/review.md +137 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/standards/draft-format.md +159 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/standards/editorial-standards.md +160 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/standards/outline-format.md +110 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/templates/avada-construction-guide.md +263 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/templates/avada-webinar-example.txt +275 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/templates/cta-block-catalog.md +169 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/templates/espo-email-preparation.md +241 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/templates/webinar-recap-email-espo.html +339 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/templates/webinar-reminder-email-espo.html +458 -0
- package/plugins/ima-claude/skills/agentic-workflows/references/workflows/editorial/webinar-summary.md +81 -0
- package/plugins/ima-claude/skills/architect/SKILL.md +54 -168
- package/plugins/ima-claude/skills/compound-bridge/SKILL.md +41 -94
- package/plugins/ima-claude/skills/design-to-code/SKILL.md +91 -0
- package/plugins/ima-claude/skills/design-to-code/references/guardrails.md +46 -0
- package/plugins/ima-claude/skills/design-to-code/references/phase-a-design-to-prompt.md +141 -0
- package/plugins/ima-claude/skills/design-to-code/references/phase-b-prompt-to-code.md +155 -0
- package/plugins/ima-claude/skills/design-to-code/references/prompt-template.md +95 -0
- package/plugins/ima-claude/skills/discourse/SKILL.md +79 -194
- package/plugins/ima-claude/skills/discourse-admin/SKILL.md +41 -103
- package/plugins/ima-claude/skills/docs-organize/SKILL.md +63 -203
- package/plugins/ima-claude/skills/ember-discourse/SKILL.md +90 -200
- package/plugins/ima-claude/skills/espocrm/SKILL.md +14 -23
- package/plugins/ima-claude/skills/espocrm-api/SKILL.md +79 -192
- package/plugins/ima-claude/skills/functional-programmer/SKILL.md +33 -237
- package/plugins/ima-claude/skills/gh-cli/SKILL.md +26 -65
- package/plugins/ima-claude/skills/ima-bootstrap/SKILL.md +71 -104
- package/plugins/ima-claude/skills/ima-bootstrap/references/ima-brand.md +32 -22
- package/plugins/ima-claude/skills/ima-brand/SKILL.md +18 -23
- package/plugins/ima-claude/skills/ima-copywriting/SKILL.md +68 -179
- package/plugins/ima-claude/skills/ima-doc2pdf/SKILL.md +32 -102
- package/plugins/ima-claude/skills/ima-editorial-scorecard/SKILL.md +38 -63
- package/plugins/ima-claude/skills/ima-editorial-workflow/SKILL.md +69 -114
- package/plugins/ima-claude/skills/ima-email-creator/SKILL.md +16 -22
- package/plugins/ima-claude/skills/ima-forms-expert/SKILL.md +21 -37
- package/plugins/ima-claude/skills/jira-checkpoint/SKILL.md +39 -120
- package/plugins/ima-claude/skills/jquery/SKILL.md +107 -233
- package/plugins/ima-claude/skills/js-fp/SKILL.md +75 -296
- package/plugins/ima-claude/skills/js-fp-api/SKILL.md +52 -162
- package/plugins/ima-claude/skills/js-fp-react/SKILL.md +47 -270
- package/plugins/ima-claude/skills/js-fp-vue/SKILL.md +55 -209
- package/plugins/ima-claude/skills/js-fp-wordpress/SKILL.md +59 -204
- package/plugins/ima-claude/skills/livecanvas/SKILL.md +19 -32
- package/plugins/ima-claude/skills/mcp-atlassian/SKILL.md +146 -136
- package/plugins/ima-claude/skills/mcp-atlassian/references/direct-api-attachments.md +115 -0
- package/plugins/ima-claude/skills/mcp-atlassian/references/direct-api-auth.md +103 -0
- package/plugins/ima-claude/skills/mcp-atlassian/references/direct-api-bulk.md +149 -0
- package/plugins/ima-claude/skills/mcp-atlassian/references/direct-api-misc.md +195 -0
- package/plugins/ima-claude/skills/mcp-atlassian/references/direct-api-sprints.md +158 -0
- package/plugins/ima-claude/skills/mcp-context7/SKILL.md +32 -64
- package/plugins/ima-claude/skills/mcp-gitea/SKILL.md +98 -188
- package/plugins/ima-claude/skills/mcp-github/SKILL.md +60 -124
- package/plugins/ima-claude/skills/mcp-memory/SKILL.md +1 -177
- package/plugins/ima-claude/skills/mcp-qdrant/SKILL.md +58 -115
- package/plugins/ima-claude/skills/mcp-sequential/SKILL.md +32 -87
- package/plugins/ima-claude/skills/mcp-serena/SKILL.md +54 -80
- package/plugins/ima-claude/skills/mcp-tavily/SKILL.md +40 -63
- package/plugins/ima-claude/skills/mcp-vestige/SKILL.md +75 -116
- package/plugins/ima-claude/skills/php-authnet/SKILL.md +32 -65
- package/plugins/ima-claude/skills/php-fp/SKILL.md +50 -129
- package/plugins/ima-claude/skills/php-fp-wordpress/SKILL.md +25 -73
- package/plugins/ima-claude/skills/phpunit-wp/SKILL.md +103 -463
- package/plugins/ima-claude/skills/playwright/SKILL.md +69 -220
- package/plugins/ima-claude/skills/prompt-starter/SKILL.md +35 -82
- package/plugins/ima-claude/skills/prompt-starter/references/code-review.md +38 -0
- package/plugins/ima-claude/skills/py-fp/SKILL.md +78 -384
- package/plugins/ima-claude/skills/quasar-fp/SKILL.md +54 -255
- package/plugins/ima-claude/skills/quickstart/SKILL.md +7 -11
- package/plugins/ima-claude/skills/rails/SKILL.md +63 -184
- package/plugins/ima-claude/skills/resume-session/SKILL.md +14 -35
- package/plugins/ima-claude/skills/rg/SKILL.md +61 -146
- package/plugins/ima-claude/skills/ruby-fp/SKILL.md +66 -163
- package/plugins/ima-claude/skills/save-session/SKILL.md +10 -39
- package/plugins/ima-claude/skills/scorecard/SKILL.md +24 -38
- package/plugins/ima-claude/skills/skill-analyzer/SKILL.md +42 -71
- package/plugins/ima-claude/skills/skill-creator/SKILL.md +79 -250
- package/plugins/ima-claude/skills/task-master/SKILL.md +11 -31
- package/plugins/ima-claude/skills/task-planner/SKILL.md +44 -153
- package/plugins/ima-claude/skills/task-runner/SKILL.md +61 -143
- package/plugins/ima-claude/skills/unit-testing/SKILL.md +59 -134
- package/plugins/ima-claude/skills/wp-ddev/SKILL.md +38 -120
- package/plugins/ima-claude/skills/wp-local/SKILL.md +26 -108
|
@@ -5,23 +5,14 @@ description: "End-to-end testing and QA automation with Playwright + TypeScript.
|
|
|
5
5
|
|
|
6
6
|
# Playwright + QA Automation
|
|
7
7
|
|
|
8
|
-
E2E testing with Playwright and TypeScript.
|
|
8
|
+
E2E testing with Playwright and TypeScript.
|
|
9
9
|
|
|
10
|
-
## QA Strategy
|
|
10
|
+
## QA Strategy
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
E2E tests are expensive. Use them strategically:
|
|
15
|
-
|
|
16
|
-
- **Test critical user journeys** — login, checkout, signup, core workflows
|
|
17
|
-
- **Don't duplicate unit test coverage** — if business logic is tested in unit tests, don't re-test it through the UI
|
|
18
|
-
- **Test integration points** — where frontend meets backend, where data flows between systems
|
|
19
|
-
- **Test what users actually do** — real workflows, not implementation details
|
|
20
|
-
|
|
21
|
-
### What Makes a Good E2E Test
|
|
12
|
+
Test critical user journeys (login, checkout, signup). Don't duplicate unit test coverage. Test integration points and real workflows, not implementation details. Each test must be self-contained — set up its own data via API, never depend on another test's state.
|
|
22
13
|
|
|
23
14
|
```typescript
|
|
24
|
-
// GOOD:
|
|
15
|
+
// GOOD: Real user journey
|
|
25
16
|
test('user completes checkout flow', async ({ page }) => {
|
|
26
17
|
await page.goto('/products')
|
|
27
18
|
await page.getByRole('button', { name: 'Add to cart' }).first().click()
|
|
@@ -30,43 +21,23 @@ test('user completes checkout flow', async ({ page }) => {
|
|
|
30
21
|
await expect(page.getByText('Order confirmed')).toBeVisible()
|
|
31
22
|
})
|
|
32
23
|
|
|
33
|
-
// BAD:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
await page.click('#product-123 > .btn-primary') // brittle
|
|
37
|
-
await page.waitForTimeout(2000) // never do this
|
|
38
|
-
expect(await page.locator('.cart-count').innerText()).toBe('1') // manual assertion
|
|
39
|
-
})
|
|
24
|
+
// BAD: Brittle selectors + hard waits
|
|
25
|
+
await page.click('#product-123 > .btn-primary')
|
|
26
|
+
await page.waitForTimeout(2000) // never do this
|
|
40
27
|
```
|
|
41
28
|
|
|
42
|
-
### Test Independence
|
|
43
|
-
|
|
44
|
-
Each test must be self-contained:
|
|
45
|
-
- Set up its own data (via API calls, not UI when possible)
|
|
46
|
-
- Clean up after itself (or use fresh browser contexts — Playwright's default)
|
|
47
|
-
- Never depend on another test's state or execution order
|
|
48
|
-
|
|
49
29
|
## Locator Strategy
|
|
50
30
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
|
54
|
-
|
|
55
|
-
|
|
|
56
|
-
|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
| 5 | Test ID | `getByTestId('submit-btn')` | Stable, explicit contract |
|
|
60
|
-
| 6 | CSS/XPath | `locator('.btn-primary')` | Last resort only |
|
|
31
|
+
| Priority | Locator | Example |
|
|
32
|
+
|----------|---------|---------|
|
|
33
|
+
| 1 | Role | `getByRole('button', { name: 'Submit' })` |
|
|
34
|
+
| 2 | Label | `getByLabel('Email address')` |
|
|
35
|
+
| 3 | Placeholder | `getByPlaceholder('Enter email')` |
|
|
36
|
+
| 4 | Text | `getByText('Welcome back')` |
|
|
37
|
+
| 5 | Test ID | `getByTestId('submit-btn')` |
|
|
38
|
+
| 6 | CSS/XPath | `locator('.btn-primary')` — last resort |
|
|
61
39
|
|
|
62
40
|
```typescript
|
|
63
|
-
// Prefer semantic locators
|
|
64
|
-
await page.getByRole('button', { name: 'Save changes' }).click()
|
|
65
|
-
await page.getByLabel('Email').fill('user@example.com')
|
|
66
|
-
|
|
67
|
-
// Use test IDs when no semantic option exists
|
|
68
|
-
await page.getByTestId('chart-container').isVisible()
|
|
69
|
-
|
|
70
41
|
// Scoped locators for disambiguation
|
|
71
42
|
const dialog = page.getByRole('dialog')
|
|
72
43
|
await dialog.getByRole('button', { name: 'Confirm' }).click()
|
|
@@ -77,49 +48,29 @@ await page.getByRole('listitem').filter({ hasText: 'Product A' }).click()
|
|
|
77
48
|
|
|
78
49
|
## Assertions
|
|
79
50
|
|
|
80
|
-
|
|
51
|
+
Always use web-first assertions — they auto-wait and retry.
|
|
81
52
|
|
|
82
53
|
```typescript
|
|
83
|
-
// CORRECT: Web-first
|
|
54
|
+
// CORRECT: Web-first (auto-wait + retry)
|
|
84
55
|
await expect(page.getByText('Success')).toBeVisible()
|
|
85
56
|
await expect(page.getByRole('heading')).toHaveText('Dashboard')
|
|
86
57
|
await expect(page).toHaveURL(/\/dashboard/)
|
|
87
|
-
await expect(page).toHaveTitle('My App - Dashboard')
|
|
88
58
|
|
|
89
|
-
// WRONG:
|
|
59
|
+
// WRONG: Race condition
|
|
90
60
|
expect(await page.getByText('Success').isVisible()).toBe(true)
|
|
91
|
-
const text = await page.locator('h1').innerText()
|
|
92
|
-
expect(text).toBe('Dashboard')
|
|
93
61
|
```
|
|
94
62
|
|
|
95
|
-
|
|
96
|
-
|
|
63
|
+
Key assertions:
|
|
97
64
|
```typescript
|
|
98
|
-
|
|
99
|
-
await expect(locator).
|
|
100
|
-
await expect(locator).
|
|
101
|
-
|
|
102
|
-
// Text content
|
|
103
|
-
await expect(locator).toHaveText('exact text')
|
|
104
|
-
await expect(locator).toContainText('partial')
|
|
105
|
-
|
|
106
|
-
// Input state
|
|
107
|
-
await expect(locator).toHaveValue('test@example.com')
|
|
108
|
-
await expect(locator).toBeChecked()
|
|
109
|
-
await expect(locator).toBeDisabled()
|
|
110
|
-
|
|
111
|
-
// Count
|
|
65
|
+
await expect(locator).toBeVisible() / toBeHidden()
|
|
66
|
+
await expect(locator).toHaveText('exact') / toContainText('partial')
|
|
67
|
+
await expect(locator).toHaveValue('val') / toBeChecked() / toBeDisabled()
|
|
112
68
|
await expect(page.getByRole('listitem')).toHaveCount(3)
|
|
113
|
-
|
|
114
|
-
// Page-level
|
|
115
|
-
await expect(page).toHaveURL(/dashboard/)
|
|
116
|
-
await expect(page).toHaveTitle(/Dashboard/)
|
|
69
|
+
await expect(page).toHaveURL(/dashboard/) / toHaveTitle(/Dashboard/)
|
|
117
70
|
```
|
|
118
71
|
|
|
119
72
|
## Page Object Model
|
|
120
73
|
|
|
121
|
-
Encapsulate page interactions in classes. Tests read like user stories.
|
|
122
|
-
|
|
123
74
|
```typescript
|
|
124
75
|
// pages/LoginPage.ts
|
|
125
76
|
import { type Page, type Locator, expect } from '@playwright/test'
|
|
@@ -137,44 +88,30 @@ export class LoginPage {
|
|
|
137
88
|
this.errorMessage = page.getByRole('alert')
|
|
138
89
|
}
|
|
139
90
|
|
|
140
|
-
async goto() {
|
|
141
|
-
await this.page.goto('/login')
|
|
142
|
-
}
|
|
143
|
-
|
|
91
|
+
async goto() { await this.page.goto('/login') }
|
|
144
92
|
async login(email: string, password: string) {
|
|
145
93
|
await this.emailInput.fill(email)
|
|
146
94
|
await this.passwordInput.fill(password)
|
|
147
95
|
await this.submitButton.click()
|
|
148
96
|
}
|
|
149
|
-
|
|
150
97
|
async expectError(message: string) {
|
|
151
98
|
await expect(this.errorMessage).toContainText(message)
|
|
152
99
|
}
|
|
153
100
|
}
|
|
154
101
|
```
|
|
155
102
|
|
|
156
|
-
###
|
|
103
|
+
### Fixtures
|
|
104
|
+
|
|
105
|
+
Register page objects as fixtures instead of beforeEach/afterEach:
|
|
157
106
|
|
|
158
107
|
```typescript
|
|
159
108
|
// fixtures.ts
|
|
160
109
|
import { test as base } from '@playwright/test'
|
|
161
110
|
import { LoginPage } from './pages/LoginPage'
|
|
162
|
-
import { DashboardPage } from './pages/DashboardPage'
|
|
163
|
-
|
|
164
|
-
type Fixtures = {
|
|
165
|
-
loginPage: LoginPage
|
|
166
|
-
dashboardPage: DashboardPage
|
|
167
|
-
}
|
|
168
111
|
|
|
169
|
-
export const test = base.extend<
|
|
170
|
-
loginPage: async ({ page }, use) => {
|
|
171
|
-
await use(new LoginPage(page))
|
|
172
|
-
},
|
|
173
|
-
dashboardPage: async ({ page }, use) => {
|
|
174
|
-
await use(new DashboardPage(page))
|
|
175
|
-
},
|
|
112
|
+
export const test = base.extend<{ loginPage: LoginPage }>({
|
|
113
|
+
loginPage: async ({ page }, use) => { await use(new LoginPage(page)) },
|
|
176
114
|
})
|
|
177
|
-
|
|
178
115
|
export { expect } from '@playwright/test'
|
|
179
116
|
```
|
|
180
117
|
|
|
@@ -187,35 +124,9 @@ test('successful login redirects to dashboard', async ({ loginPage, dashboardPag
|
|
|
187
124
|
await loginPage.login('user@example.com', 'password123')
|
|
188
125
|
await expect(dashboardPage.heading).toBeVisible()
|
|
189
126
|
})
|
|
190
|
-
|
|
191
|
-
test('invalid credentials show error', async ({ loginPage }) => {
|
|
192
|
-
await loginPage.goto()
|
|
193
|
-
await loginPage.login('user@example.com', 'wrong')
|
|
194
|
-
await loginPage.expectError('Invalid credentials')
|
|
195
|
-
})
|
|
196
127
|
```
|
|
197
128
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
Fixtures provide reusable setup/teardown. Use them instead of beforeEach/afterEach.
|
|
201
|
-
|
|
202
|
-
```typescript
|
|
203
|
-
// fixtures.ts — authenticated user fixture
|
|
204
|
-
export const test = base.extend<{
|
|
205
|
-
authenticatedPage: Page
|
|
206
|
-
}>({
|
|
207
|
-
authenticatedPage: async ({ browser }, use) => {
|
|
208
|
-
const context = await browser.newContext({
|
|
209
|
-
storageState: 'auth/user.json' // pre-saved auth state
|
|
210
|
-
})
|
|
211
|
-
const page = await context.newPage()
|
|
212
|
-
await use(page)
|
|
213
|
-
await context.close()
|
|
214
|
-
},
|
|
215
|
-
})
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### Save Auth State (Global Setup)
|
|
129
|
+
### Auth State (Global Setup)
|
|
219
130
|
|
|
220
131
|
```typescript
|
|
221
132
|
// global-setup.ts
|
|
@@ -232,39 +143,28 @@ export default async function globalSetup(config: FullConfig) {
|
|
|
232
143
|
await page.context().storageState({ path: 'auth/user.json' })
|
|
233
144
|
await browser.close()
|
|
234
145
|
}
|
|
146
|
+
|
|
147
|
+
// fixture usage
|
|
148
|
+
authenticatedPage: async ({ browser }, use) => {
|
|
149
|
+
const context = await browser.newContext({ storageState: 'auth/user.json' })
|
|
150
|
+
const page = await context.newPage()
|
|
151
|
+
await use(page)
|
|
152
|
+
await context.close()
|
|
153
|
+
}
|
|
235
154
|
```
|
|
236
155
|
|
|
237
156
|
## Project Structure
|
|
238
157
|
|
|
239
158
|
```
|
|
240
159
|
tests/
|
|
241
|
-
├── e2e/
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
│ ├── checkout/
|
|
246
|
-
│ │ └── purchase-flow.spec.ts
|
|
247
|
-
│ └── dashboard/
|
|
248
|
-
│ └── widgets.spec.ts
|
|
249
|
-
├── pages/
|
|
250
|
-
│ ├── LoginPage.ts
|
|
251
|
-
│ ├── DashboardPage.ts
|
|
252
|
-
│ └── CheckoutPage.ts
|
|
253
|
-
├── components/
|
|
254
|
-
│ ├── Modal.ts
|
|
255
|
-
│ ├── DataTable.ts
|
|
256
|
-
│ └── Navigation.ts
|
|
257
|
-
├── fixtures.ts
|
|
160
|
+
├── e2e/ # Test specs grouped by feature
|
|
161
|
+
├── pages/ # One page object per page/section
|
|
162
|
+
├── components/ # Shared: Modal.ts, DataTable.ts, Navigation.ts
|
|
163
|
+
├── fixtures.ts # Extended test object (single export)
|
|
258
164
|
├── global-setup.ts
|
|
259
165
|
└── playwright.config.ts
|
|
260
166
|
```
|
|
261
167
|
|
|
262
|
-
**Guidelines**:
|
|
263
|
-
- One page object per page/major section
|
|
264
|
-
- Shared components (modals, tables, nav) get their own classes in `components/`
|
|
265
|
-
- Tests grouped by feature area
|
|
266
|
-
- Single `fixtures.ts` exports the extended `test` object
|
|
267
|
-
|
|
268
168
|
## Configuration
|
|
269
169
|
|
|
270
170
|
```typescript
|
|
@@ -279,14 +179,12 @@ export default defineConfig({
|
|
|
279
179
|
workers: process.env.CI ? 1 : undefined,
|
|
280
180
|
reporter: process.env.CI ? 'blob' : 'html',
|
|
281
181
|
globalSetup: './tests/global-setup.ts',
|
|
282
|
-
|
|
283
182
|
use: {
|
|
284
183
|
baseURL: process.env.BASE_URL ?? 'http://localhost:3000',
|
|
285
184
|
trace: 'on-first-retry',
|
|
286
185
|
screenshot: 'only-on-failure',
|
|
287
186
|
video: 'retain-on-failure',
|
|
288
187
|
},
|
|
289
|
-
|
|
290
188
|
projects: [
|
|
291
189
|
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
|
|
292
190
|
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
|
|
@@ -294,7 +192,6 @@ export default defineConfig({
|
|
|
294
192
|
{ name: 'mobile-chrome', use: { ...devices['Pixel 5'] } },
|
|
295
193
|
{ name: 'mobile-safari', use: { ...devices['iPhone 13'] } },
|
|
296
194
|
],
|
|
297
|
-
|
|
298
195
|
webServer: {
|
|
299
196
|
command: 'npm run dev',
|
|
300
197
|
url: 'http://localhost:3000',
|
|
@@ -303,17 +200,17 @@ export default defineConfig({
|
|
|
303
200
|
})
|
|
304
201
|
```
|
|
305
202
|
|
|
306
|
-
## Network Mocking
|
|
203
|
+
## Network Mocking
|
|
307
204
|
|
|
308
205
|
```typescript
|
|
309
|
-
// Mock
|
|
206
|
+
// Mock endpoint
|
|
310
207
|
await page.route('**/api/users', route => route.fulfill({
|
|
311
208
|
status: 200,
|
|
312
209
|
contentType: 'application/json',
|
|
313
210
|
body: JSON.stringify([{ id: 1, name: 'Test User' }]),
|
|
314
211
|
}))
|
|
315
212
|
|
|
316
|
-
// Modify
|
|
213
|
+
// Modify real response
|
|
317
214
|
await page.route('**/api/products', async route => {
|
|
318
215
|
const response = await route.fetch()
|
|
319
216
|
const json = await response.json()
|
|
@@ -321,114 +218,66 @@ await page.route('**/api/products', async route => {
|
|
|
321
218
|
await route.fulfill({ response, json })
|
|
322
219
|
})
|
|
323
220
|
|
|
324
|
-
// Block resources
|
|
221
|
+
// Block resources
|
|
325
222
|
await page.route('**/*.{png,jpg,gif}', route => route.abort())
|
|
326
223
|
|
|
327
224
|
// Add auth headers
|
|
328
|
-
await page.route('**/api/**', route =>
|
|
329
|
-
route.continue({
|
|
330
|
-
|
|
331
|
-
})
|
|
332
|
-
})
|
|
225
|
+
await page.route('**/api/**', route =>
|
|
226
|
+
route.continue({ headers: { ...route.request().headers(), Authorization: 'Bearer test-token' } })
|
|
227
|
+
)
|
|
333
228
|
```
|
|
334
229
|
|
|
335
|
-
|
|
230
|
+
See [references/network-mocking.md](references/network-mocking.md) for HAR recording, API-first setup, error simulation.
|
|
336
231
|
|
|
337
|
-
## Visual Regression
|
|
232
|
+
## Visual Regression
|
|
338
233
|
|
|
339
234
|
```typescript
|
|
340
|
-
// Full page screenshot comparison
|
|
341
235
|
await expect(page).toHaveScreenshot()
|
|
342
|
-
|
|
343
|
-
// Element-level comparison
|
|
344
236
|
await expect(page.getByTestId('chart')).toHaveScreenshot('chart.png')
|
|
345
|
-
|
|
346
|
-
// With tolerance for minor rendering differences
|
|
347
237
|
await expect(page).toHaveScreenshot({ maxDiffPixelRatio: 0.01 })
|
|
348
|
-
|
|
349
238
|
// Update baselines: npx playwright test --update-snapshots
|
|
350
239
|
```
|
|
351
240
|
|
|
352
|
-
|
|
241
|
+
See [references/visual-regression.md](references/visual-regression.md) for deterministic screenshots and CI strategies.
|
|
353
242
|
|
|
354
243
|
## Debugging
|
|
355
244
|
|
|
356
245
|
```bash
|
|
357
|
-
#
|
|
358
|
-
npx playwright test --
|
|
359
|
-
|
|
360
|
-
# Run with headed browser
|
|
361
|
-
npx playwright test --headed
|
|
362
|
-
|
|
363
|
-
# Run with step-by-step trace viewer
|
|
364
|
-
npx playwright test --trace on
|
|
365
|
-
|
|
366
|
-
# Debug a specific test
|
|
246
|
+
npx playwright test --ui # Interactive UI mode
|
|
247
|
+
npx playwright test --headed # Headed browser
|
|
248
|
+
npx playwright test --trace on # Step-by-step trace
|
|
367
249
|
npx playwright test -g "login" --debug
|
|
368
|
-
|
|
369
|
-
# View last test report
|
|
370
250
|
npx playwright show-report
|
|
371
251
|
```
|
|
372
252
|
|
|
373
253
|
```typescript
|
|
374
|
-
// Pause
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
// Slow down actions for visual debugging
|
|
378
|
-
// In config: use: { launchOptions: { slowMo: 500 } }
|
|
254
|
+
await page.pause() // Pause for manual inspection
|
|
255
|
+
// Slow actions: use: { launchOptions: { slowMo: 500 } }
|
|
379
256
|
```
|
|
380
257
|
|
|
381
258
|
## Anti-Patterns
|
|
382
259
|
|
|
383
260
|
```typescript
|
|
384
|
-
// NEVER:
|
|
385
|
-
await page.
|
|
386
|
-
|
|
387
|
-
// NEVER:
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
// NEVER: Manual assertions without retry
|
|
391
|
-
const text = await page.locator('.status').innerText()
|
|
392
|
-
expect(text).toBe('Ready') // Race condition — use web-first assertions
|
|
393
|
-
|
|
394
|
-
// NEVER: Testing third-party dependencies
|
|
395
|
-
await page.goto('https://external-service.com/verify') // Mock it instead
|
|
396
|
-
|
|
397
|
-
// NEVER: Shared mutable state between tests
|
|
398
|
-
let sharedUser // Each test gets its own state via fixtures
|
|
399
|
-
|
|
400
|
-
// NEVER: Skipping cleanup
|
|
401
|
-
// Use fixtures — they handle teardown automatically
|
|
261
|
+
await page.waitForTimeout(3000) // NEVER: hard wait
|
|
262
|
+
await page.click('#app > div:nth-child(2) > button') // NEVER: brittle CSS
|
|
263
|
+
expect(await page.locator('.status').innerText()).toBe('Ready') // NEVER: race condition
|
|
264
|
+
await page.goto('https://external-service.com/verify') // NEVER: test third-party
|
|
265
|
+
let sharedUser // NEVER: shared mutable state between tests
|
|
402
266
|
```
|
|
403
267
|
|
|
404
268
|
## Linting
|
|
405
269
|
|
|
406
|
-
Use `eslint-plugin-playwright` to catch common mistakes:
|
|
407
|
-
|
|
408
270
|
```bash
|
|
409
271
|
npm install -D eslint-plugin-playwright
|
|
410
272
|
```
|
|
411
273
|
|
|
412
|
-
|
|
413
|
-
- Missing `await` on async Playwright calls
|
|
414
|
-
- Using `page.waitForTimeout` (prefer auto-waiting)
|
|
415
|
-
- Manual assertions instead of web-first assertions
|
|
416
|
-
- Using forbidden selectors (nth-child, etc.)
|
|
274
|
+
Catches: missing `await`, `waitForTimeout` usage, manual assertions, forbidden selectors.
|
|
417
275
|
|
|
418
276
|
## Reference Files
|
|
419
277
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
**When**: Screenshot comparisons, deterministic rendering, CI screenshot strategies, animation handling
|
|
427
|
-
|
|
428
|
-
### Accessibility Testing
|
|
429
|
-
**File**: [references/accessibility-testing.md](references/accessibility-testing.md)
|
|
430
|
-
**When**: WCAG compliance audits, axe-core integration, accessibility fixtures, automated a11y checks
|
|
431
|
-
|
|
432
|
-
### CI/CD Integration
|
|
433
|
-
**File**: [references/ci-cd.md](references/ci-cd.md)
|
|
434
|
-
**When**: GitHub Actions setup, sharding, parallelism, artifact management, Docker, reporting strategies
|
|
278
|
+
| File | When |
|
|
279
|
+
|------|------|
|
|
280
|
+
| [references/network-mocking.md](references/network-mocking.md) | HAR recording, intercepting, error simulation |
|
|
281
|
+
| [references/visual-regression.md](references/visual-regression.md) | Screenshot CI, animation handling |
|
|
282
|
+
| [references/accessibility-testing.md](references/accessibility-testing.md) | WCAG audits, axe-core, a11y fixtures |
|
|
283
|
+
| [references/ci-cd.md](references/ci-cd.md) | GitHub Actions, sharding, artifacts, Docker |
|
|
@@ -1,128 +1,81 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: prompt-starter
|
|
3
|
-
description:
|
|
3
|
+
description: Build better prompts from rough ideas. Selects template, pre-fills from Jira, opens in GUI editor, returns refined prompt. Does NOT execute the work — only crafts the prompt.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Prompt Starter
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
**Trigger words:**
|
|
11
|
-
- `brainstorm`, `research`, `explore` → `references/brainstorm.md`
|
|
12
|
-
- `plan`, `implement`, `build`, `execute` → `references/plan-implement.md`
|
|
13
|
-
- `quick`, or a short one-liner task → `references/quick.md`
|
|
14
|
-
- Just a Jira key with no clear workflow → ask the user which template
|
|
15
|
-
|
|
16
|
-
## Relationship to prompt_coach.py
|
|
8
|
+
**Role: prompt builder, not executor.** Take a rough idea, produce a well-structured prompt. Never execute the work described — only craft and return it.
|
|
17
9
|
|
|
18
10
|
- **prompt-starter** = "What should my prompt say?" (template + context + editor)
|
|
19
11
|
- **prompt_coach.py** = "Is my prompt good enough?" (quality evaluation)
|
|
20
12
|
|
|
21
|
-
Different lanes, complementary. The coach may fire on the final prompt — that's fine.
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
13
|
## Template Selection
|
|
26
14
|
|
|
27
|
-
Match the user's trigger words to select a template. Examples:
|
|
28
|
-
|
|
29
15
|
| User says | Template |
|
|
30
16
|
|---|---|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
| "FNR-1234" (ambiguous) | Ask which workflow |
|
|
37
|
-
|
|
38
|
-
---
|
|
17
|
+
| `brainstorm`, `research`, `explore` | `references/brainstorm.md` |
|
|
18
|
+
| `plan`, `implement`, `build`, `execute` | `references/plan-implement.md` |
|
|
19
|
+
| `review`, `code review`, `audit`, `PR review`, Gitea/GitHub PR URL | `references/code-review.md` |
|
|
20
|
+
| `quick` or short one-liner | `references/quick.md` |
|
|
21
|
+
| Jira key only (ambiguous) | Ask which template |
|
|
39
22
|
|
|
40
23
|
## Flow
|
|
41
24
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
Read the appropriate template from `references/`.
|
|
25
|
+
**Step 1: Select template** — read from `references/`.
|
|
45
26
|
|
|
46
|
-
|
|
27
|
+
**Step 2: Fetch Jira context** (if key present) — use mcp-atlassian. Map fields to template `[bracket]` placeholders:
|
|
28
|
+
- Summary → one-line goal / user story
|
|
29
|
+
- Description → Problem section
|
|
30
|
+
- Acceptance Criteria → Acceptance / Test sections
|
|
31
|
+
- For code-review template: PR URL or branch from description/linked branch → pre-fill `Scope` section
|
|
47
32
|
|
|
48
|
-
Use
|
|
49
|
-
- **Summary** → fills the one-line goal / user story
|
|
50
|
-
- **Description** → fills the Problem section
|
|
51
|
-
- **Acceptance Criteria** (from description or subtasks) → fills Acceptance / Test sections
|
|
33
|
+
Use judgment — if Jira description is sparse, leave bracket hints for user.
|
|
52
34
|
|
|
53
|
-
|
|
35
|
+
**Step 3: Check prior work** (plan-implement only) — search Serena memory for `{feature-name}-brainstorm`. If found, pre-fill Prior Work section and incorporate key decisions into Plan section.
|
|
54
36
|
|
|
55
|
-
|
|
37
|
+
**Step 4: Write pre-filled template**
|
|
56
38
|
|
|
57
|
-
For plan-implement templates, search Serena memory for `{feature-name}-brainstorm`. If found, pre-fill the **Prior Work** section with a reference to it and incorporate key decisions into the **Plan** section.
|
|
58
|
-
|
|
59
|
-
### Step 4: Write the pre-filled template
|
|
60
|
-
|
|
61
|
-
Create the prompt directory if needed:
|
|
62
39
|
```bash
|
|
63
40
|
mkdir -p ~/.claude/prompts
|
|
64
41
|
```
|
|
65
42
|
|
|
66
|
-
Write
|
|
43
|
+
Write to `~/.claude/prompts/{session-name}.md` — name descriptively:
|
|
67
44
|
- `brainstorm-pdf-export.md`
|
|
68
45
|
- `quick-email-validation.md`
|
|
69
46
|
- `plan-fnr-1234.md`
|
|
70
47
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
**Quick template exception:** Quick templates are short (12 lines). Present them inline in the conversation — no editor spawn. Skip to Step 7.
|
|
48
|
+
**Step 5: Open in editor**
|
|
74
49
|
|
|
75
|
-
|
|
50
|
+
Quick templates (12 lines): present inline, skip editor. Go to Step 7.
|
|
76
51
|
|
|
77
|
-
|
|
52
|
+
For brainstorm and plan-implement, spawn GUI editor. Claude Code owns the terminal — terminal editors (nano, vim) cannot be used.
|
|
78
53
|
|
|
79
|
-
|
|
54
|
+
Editor resolution order:
|
|
55
|
+
1. `$VISUAL`
|
|
56
|
+
2. `$EDITOR` — only if known GUI: `zed`, `code`, `subl`, `gedit`, `kate`
|
|
57
|
+
3. Auto-detect: `which zed` → `which code` → `which subl` (first found)
|
|
58
|
+
4. Fallback: present inline, edit via conversation
|
|
80
59
|
|
|
81
|
-
Resolution order:
|
|
82
|
-
1. `$VISUAL` — the Unix convention for GUI editors
|
|
83
|
-
2. `$EDITOR` — but **only** if it's a known GUI editor: `zed`, `code`, `subl`, `gedit`, `kate`
|
|
84
|
-
3. Auto-detect: check `which zed`, then `which code`, then `which subl` — use the first found
|
|
85
|
-
4. **Fallback:** no suitable editor found → present inline and modify via conversation
|
|
86
|
-
|
|
87
|
-
#### Spawning the editor
|
|
88
|
-
|
|
89
|
-
Use Bash with `run_in_background: true`:
|
|
90
60
|
```bash
|
|
61
|
+
# Spawn with run_in_background: true
|
|
91
62
|
zed --wait ~/.claude/prompts/{session-name}.md
|
|
92
63
|
```
|
|
93
64
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
Tell the user:
|
|
97
|
-
> Template is open in {editor}. Edit and close the tab when done — I'll pick up from there.
|
|
65
|
+
Tell user: `"Template is open in {editor}. Edit and close the tab when done — I'll pick up from there."`
|
|
98
66
|
|
|
99
|
-
|
|
67
|
+
**Step 6: Read result** — when background task completes, read `~/.claude/prompts/{session-name}.md`.
|
|
100
68
|
|
|
101
|
-
|
|
102
|
-
```
|
|
103
|
-
Read ~/.claude/prompts/{session-name}.md
|
|
104
|
-
```
|
|
69
|
+
**Step 7: Present finished prompt — STOP**
|
|
105
70
|
|
|
106
|
-
|
|
71
|
+
> Here's your refined prompt. You can paste it into a new conversation, adjust it further, or tell me to run it.
|
|
107
72
|
|
|
108
|
-
|
|
109
|
-
> Here's your prompt. Ready to execute, or want to adjust anything?
|
|
73
|
+
Do NOT execute. Only execute if user explicitly says "run it" or "execute this".
|
|
110
74
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
## Editor Notes for Team Onboarding
|
|
116
|
-
|
|
117
|
-
Team members should set `$VISUAL` in their shell profile for the best experience:
|
|
75
|
+
## Team Setup
|
|
118
76
|
|
|
119
77
|
```bash
|
|
120
|
-
# Zed
|
|
121
|
-
echo 'export VISUAL="
|
|
122
|
-
|
|
123
|
-
# VS Code
|
|
124
|
-
echo 'export VISUAL="code --wait"' >> ~/.bashrc
|
|
125
|
-
|
|
126
|
-
# Sublime Text
|
|
127
|
-
echo 'export VISUAL="subl --wait"' >> ~/.bashrc
|
|
78
|
+
echo 'export VISUAL="zed --wait"' >> ~/.bashrc # Zed
|
|
79
|
+
echo 'export VISUAL="code --wait"' >> ~/.bashrc # VS Code
|
|
80
|
+
echo 'export VISUAL="subl --wait"' >> ~/.bashrc # Sublime Text
|
|
128
81
|
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Code Review
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
Review [PR URL | branch | file paths] for [correctness | security | FP compliance | all]
|
|
5
|
+
|
|
6
|
+
## Scope
|
|
7
|
+
- PR / branch / commit: [URL or ref]
|
|
8
|
+
- Files / modules: [paths or Serena symbol names — leave blank for all]
|
|
9
|
+
- Stack: [PHP | WordPress | JS | jQuery | React | Vue | etc.]
|
|
10
|
+
|
|
11
|
+
## Review focus
|
|
12
|
+
- [ ] Correctness — logic errors, edge cases, null paths
|
|
13
|
+
- [ ] Security — input validation, SQL injection, XSS, auth/authz, secrets
|
|
14
|
+
- [ ] FP — mutation, side effects, over-engineering, custom utilities over native
|
|
15
|
+
- [ ] Quality — naming, dead code, pattern consistency
|
|
16
|
+
- [ ] WordPress — nonce verification, capability checks, escaping
|
|
17
|
+
- [ ] [other]
|
|
18
|
+
|
|
19
|
+
## Pattern (proven)
|
|
20
|
+
Use `/ima-claude:task-master` to orchestrate:
|
|
21
|
+
1. Delegate to `/ima-claude:explorer` first — understand scope and surrounding context via Serena (not diff-only)
|
|
22
|
+
2. Delegate to `/ima-claude:reviewer` with domain skills: [php-fp, php-fp-wordpress, js-fp, js-fp-wordpress, jquery, etc.]
|
|
23
|
+
3. **Advisor pass on Critical findings** — before finalizing, each Critical gets a 2nd-pass re-examination (see reviewer agent's advisor-pattern rules). Confirmed → keep; withdrawn → drop.
|
|
24
|
+
4. **Architectural findings escalate** — if reviewer returns `ESCALATION: Architectural finding`, parent (Opus) decides whether to expand scope, re-dispatch a focused follow-up, or accept for later.
|
|
25
|
+
5. Document findings in Serena as `{pr-id}-review` for audit trail.
|
|
26
|
+
|
|
27
|
+
## Do NOT
|
|
28
|
+
- Use `/code-review:code-review` (third-party) — its validation gates filter real issues
|
|
29
|
+
- Restrict reviewer to diff-only — bugs depend on surrounding context
|
|
30
|
+
- Skip the advisor pass for Critical/Warning findings
|
|
31
|
+
- Treat an architectural ESCALATION as a failed review — it's a scoped request for arbitration
|
|
32
|
+
|
|
33
|
+
## Acceptance
|
|
34
|
+
- [ ] All Critical issues have specific file:line + proposed fix
|
|
35
|
+
- [ ] Warnings include reasoning
|
|
36
|
+
- [ ] Findings saved to Serena
|
|
37
|
+
- [ ] Advisor pass confirmed (or withdrawn) before reporting Critical
|
|
38
|
+
- [ ] Any `ESCALATION:` returns handled by parent (Opus), not buried in the review
|