openspec-playwright 0.1.41 → 0.1.44
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/skills/openspec-e2e/SKILL.md +150 -201
- package/dist/commands/editors.d.ts +6 -1
- package/dist/commands/editors.js +32 -2
- package/dist/commands/editors.js.map +1 -1
- package/dist/commands/init.js +9 -2
- package/dist/commands/init.js.map +1 -1
- package/employee-standards.md +84 -0
- package/openspec-playwright-0.1.44.tgz +0 -0
- package/package.json +5 -2
- package/release-notes.md +2 -2
- package/src/commands/editors.ts +33 -2
- package/src/commands/init.ts +10 -2
- package/templates/auth.setup.ts +17 -4
- package/templates/credentials.yaml +6 -6
- package/tests/editors.test.ts +180 -0
- package/vitest.config.ts +9 -0
- package/openspec-playwright-0.1.41.tgz +0 -0
|
@@ -3,11 +3,9 @@ name: openspec-e2e
|
|
|
3
3
|
description: Run Playwright E2E verification for an OpenSpec change. Use when the user wants to validate that the implementation works end-to-end by running Playwright tests generated from the specs.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Requires openspec CLI, Playwright (with browsers installed), and @playwright/mcp (globally installed via `claude mcp add playwright npx @playwright/mcp@latest`).
|
|
6
|
-
|
|
7
|
-
**Architecture**: Uses CLI + SKILLs (not `init-agents`). This follows Playwright's recommended approach for coding agents — CLI is more token-efficient than loading MCP tool schemas into context. MCP is used only for Healer (UI inspection on failure).
|
|
8
6
|
metadata:
|
|
9
7
|
author: openspec-playwright
|
|
10
|
-
version: "2.
|
|
8
|
+
version: "2.8"
|
|
11
9
|
---
|
|
12
10
|
|
|
13
11
|
## Input
|
|
@@ -25,13 +23,9 @@ metadata:
|
|
|
25
23
|
|
|
26
24
|
## Architecture
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
- **🎭 Planner** (Step 4): Consumes OpenSpec specs (`specs/*.md`) and produces `test-plan.md` — combines OpenSpec's structured requirements with LLM编排.
|
|
31
|
-
- **🎭 Generator** (Step 5): Transforms the Markdown test-plan into real Playwright `.spec.ts` files using LLM code generation.
|
|
32
|
-
- **🎭 Healer** (Step 8): Executes the test suite and automatically repairs failing selectors via Playwright MCP tools.
|
|
26
|
+
Pipeline: **Planner** (Step 4) → **Generator** (Step 5) → **Healer** (Step 8).
|
|
33
27
|
|
|
34
|
-
Uses CLI + SKILLs (not `init-agents`).
|
|
28
|
+
Uses CLI + SKILLs (not `init-agents`). CLI is ~4x more token-efficient than loading MCP tool schemas. MCP is used only for Healer (UI inspection on failure).
|
|
35
29
|
|
|
36
30
|
**Schema owns templates. CLI handles execution. Skill handles cognitive work.**
|
|
37
31
|
|
|
@@ -56,7 +50,7 @@ If `openspec/changes/<name>/specs/` is empty, inform the user and stop. E2E requ
|
|
|
56
50
|
|
|
57
51
|
Read all files from `openspec/changes/<name>/specs/*.md`. Extract functional requirements.
|
|
58
52
|
|
|
59
|
-
Detect if auth is required
|
|
53
|
+
Detect if auth is required only when BOTH conditions are met:
|
|
60
54
|
|
|
61
55
|
**Condition A — Explicit markers**: "login", "signin", "logout", "authenticate", "protected", "authenticated", "session", "unauthorized"
|
|
62
56
|
|
|
@@ -71,169 +65,172 @@ Detect if auth is required. Mark as **auth required** only when BOTH conditions
|
|
|
71
65
|
|
|
72
66
|
### 3. Validate environment
|
|
73
67
|
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
Run the seed test before generating tests:
|
|
76
69
|
```bash
|
|
77
70
|
npx playwright test tests/playwright/seed.spec.ts --project=chromium
|
|
78
71
|
```
|
|
79
72
|
|
|
80
|
-
|
|
81
|
-
- App server is reachable (BASE_URL accessible)
|
|
82
|
-
- Auth fixtures (`storageState`) are initialized if auth is required
|
|
83
|
-
- Playwright browser and config are working
|
|
73
|
+
This validates: app server reachable, auth fixtures initialized, Playwright working.
|
|
84
74
|
|
|
85
|
-
**If seed test fails**: Stop and report
|
|
86
|
-
|
|
87
|
-
**If seed test passes or no auth required**: Proceed to Step 4.
|
|
75
|
+
**If seed test fails**: Stop and report. Fix the environment before proceeding.
|
|
88
76
|
|
|
89
77
|
### 4. Generate test plan
|
|
90
78
|
|
|
91
|
-
Create `openspec/changes/<name>/specs/playwright/test-plan.md
|
|
92
|
-
-
|
|
93
|
-
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
79
|
+
Create `openspec/changes/<name>/specs/playwright/test-plan.md`:
|
|
80
|
+
- List each functional requirement as a test case
|
|
81
|
+
- Mark with `@role(user|admin|guest|none)` and `@auth(required|none)`
|
|
82
|
+
- Include happy path AND error paths
|
|
83
|
+
- Reference the route/page each test targets
|
|
96
84
|
|
|
97
|
-
**Idempotency**: If test-plan.md already exists → read it, use it, do NOT regenerate
|
|
85
|
+
**Idempotency**: If test-plan.md already exists → read it, use it, do NOT regenerate.
|
|
98
86
|
|
|
99
|
-
### 5. Generate test file
|
|
87
|
+
### 5. Generate test file
|
|
100
88
|
|
|
101
|
-
|
|
89
|
+
Create `tests/playwright/<name>.spec.ts`:
|
|
102
90
|
|
|
103
91
|
**Read inputs first**:
|
|
104
|
-
- `openspec/changes/<name>/specs/playwright/test-plan.md`
|
|
105
|
-
- `tests/playwright/seed.spec.ts`
|
|
106
|
-
|
|
107
|
-
**Generate Playwright code
|
|
108
|
-
- Follow
|
|
109
|
-
- Prefer `data-testid
|
|
110
|
-
- Include
|
|
111
|
-
- Use `test.describe(...)` for grouping
|
|
92
|
+
- `openspec/changes/<name>/specs/playwright/test-plan.md`
|
|
93
|
+
- `tests/playwright/seed.spec.ts`
|
|
94
|
+
|
|
95
|
+
**Generate** Playwright code for each test case:
|
|
96
|
+
- Follow `seed.spec.ts` structure
|
|
97
|
+
- Prefer `data-testid`; fallback to `getByRole`, `getByLabel`, `getByText`
|
|
98
|
+
- Include happy path AND error/edge cases
|
|
99
|
+
- Use `test.describe(...)` for grouping
|
|
112
100
|
- Each test: `test('描述性名称', async ({ page }) => { ... })`
|
|
113
|
-
- Add `@project(user)` / `@project(admin)` on role-specific tests
|
|
114
101
|
|
|
115
|
-
|
|
102
|
+
#### Anti-Pattern Warnings
|
|
116
103
|
|
|
117
|
-
**🚫
|
|
104
|
+
**🚫 False Pass** — never silently skip when element is missing:
|
|
118
105
|
```typescript
|
|
119
|
-
// WRONG
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
await btn.click();
|
|
123
|
-
await expect(page.getByText('成功')).toBeVisible();
|
|
124
|
-
}
|
|
125
|
-
// ✅ CORRECT: Use assertion — test fails if element is missing
|
|
106
|
+
// WRONG
|
|
107
|
+
if (await btn.isVisible().catch(() => false)) { ... }
|
|
108
|
+
// ✅ CORRECT
|
|
126
109
|
await expect(page.getByRole('button', { name: '取消' })).toBeVisible();
|
|
127
|
-
await page.getByRole('button', { name: '取消' }).click();
|
|
128
|
-
await expect(page.getByText('成功')).toBeVisible();
|
|
129
110
|
```
|
|
130
111
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
**🚫 NEVER rely on Playwright projects for permission filtering:**
|
|
112
|
+
**🚫 Permission filtering** — use `@tag` with `--grep`, not projects:
|
|
134
113
|
```typescript
|
|
135
|
-
|
|
136
|
-
projects: [{ name: 'admin' }, { name: 'user' }]
|
|
137
|
-
|
|
138
|
-
// ✅ CORRECT: Use @tag for permission-based test filtering
|
|
139
|
-
test('admin only - activate subscription', { tag: '@admin' }, async ({ page }) => { ... });
|
|
140
|
-
test('user only - view subscription', { tag: '@user' }, async ({ page }) => { ... });
|
|
114
|
+
test('admin only', { tag: '@admin' }, async ({ page }) => { ... });
|
|
141
115
|
// Run with: npx playwright test --grep "@admin"
|
|
142
116
|
```
|
|
143
117
|
|
|
144
|
-
**🚫
|
|
145
|
-
The auth guard is a **critical security feature**. Skipping it leaves a gap in coverage.
|
|
118
|
+
**🚫 Auth guard** — test with FRESH browser context (no inherited cookies):
|
|
146
119
|
```typescript
|
|
147
|
-
// ✅ CORRECT: Test auth guard with a FRESH browser context (no cookies, no storage)
|
|
148
120
|
test('redirects unauthenticated user to login', async ({ browser }) => {
|
|
149
|
-
const
|
|
150
|
-
const freshPage = await freshContext.newPage();
|
|
121
|
+
const freshPage = await browser.newContext().newPage();
|
|
151
122
|
await freshPage.goto(`${BASE_URL}/dashboard`);
|
|
152
123
|
await expect(freshPage).toHaveURL(/login|auth/);
|
|
153
|
-
await freshContext.close();
|
|
154
124
|
});
|
|
155
125
|
```
|
|
156
126
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
- Network timeout → retry or error UX?
|
|
161
|
-
- Invalid input → validation message shown?
|
|
127
|
+
#### Playwright API Guardrails
|
|
128
|
+
|
|
129
|
+
These are the most common mistakes that cause test failures. **Always follow these rules:**
|
|
162
130
|
|
|
163
|
-
**
|
|
131
|
+
**API calls — use `request` API, NOT `page.evaluate()`:**
|
|
164
132
|
```typescript
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
test.describe('Feature Name', () => {
|
|
170
|
-
test('happy path - action succeeds', async ({ page }) => {
|
|
171
|
-
await page.goto(`${BASE_URL}/path`);
|
|
172
|
-
await page.getByTestId('element').click();
|
|
173
|
-
await expect(page.getByTestId('result')).toBeVisible();
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
test('error case - invalid input shows message', async ({ page }) => {
|
|
177
|
-
await page.goto(`${BASE_URL}/path`);
|
|
178
|
-
await page.getByTestId('input').fill('invalid');
|
|
179
|
-
await page.getByTestId('submit').click();
|
|
180
|
-
await expect(page.getByTestId('error')).toContainText('Error text');
|
|
181
|
-
});
|
|
133
|
+
// ❌ WRONG — page.evaluate timeout, wrong context, CORS issues
|
|
134
|
+
const result = await page.evaluate(async () => {
|
|
135
|
+
const res = await fetch('/api/data');
|
|
136
|
+
return res.json();
|
|
182
137
|
});
|
|
138
|
+
|
|
139
|
+
// ✅ CORRECT — direct HTTP, no browser context, fast
|
|
140
|
+
const res = await page.request.get(`${BASE_URL}/api/data`);
|
|
141
|
+
expect(res.status()).toBe(200);
|
|
142
|
+
const data = await res.json();
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Browser context cleanup — `dispose()` NOT `close()`:**
|
|
146
|
+
```typescript
|
|
147
|
+
// ❌ WRONG — close() is not a function on APIRequestContext
|
|
148
|
+
const ctx = await page.request.newContext();
|
|
149
|
+
await ctx.dispose(); // actually correct, but this is CommonContext
|
|
150
|
+
const context = await browser.newContext();
|
|
151
|
+
await context.close(); // ← WRONG
|
|
152
|
+
|
|
153
|
+
// ✅ CORRECT
|
|
154
|
+
const context = await browser.newContext();
|
|
155
|
+
await context.close(); // close() is correct for BrowserContext
|
|
156
|
+
|
|
157
|
+
// For APIRequestContext (from page.request):
|
|
158
|
+
// No cleanup needed — it's managed by Playwright automatically
|
|
183
159
|
```
|
|
184
160
|
|
|
185
|
-
**
|
|
161
|
+
**File uploads — use `setInputFiles()`, NOT `page.evaluate()` + fetch:**
|
|
162
|
+
```typescript
|
|
163
|
+
// ❌ WRONG
|
|
164
|
+
await page.evaluate(() => {
|
|
165
|
+
const input = document.querySelector('input[type=file]');
|
|
166
|
+
// ...
|
|
167
|
+
});
|
|
186
168
|
|
|
187
|
-
|
|
169
|
+
// ✅ CORRECT
|
|
170
|
+
await page.locator('input[type="file"]').setInputFiles('/path/to/file.pdf');
|
|
171
|
+
```
|
|
188
172
|
|
|
189
|
-
|
|
173
|
+
**Form submissions — prefer Playwright locators, not JS clicks:**
|
|
174
|
+
```typescript
|
|
175
|
+
// ❌ WRONG — bypasses Playwright's actionability checks
|
|
176
|
+
await page.evaluate(() => document.querySelector('button[type=submit]').click());
|
|
190
177
|
|
|
191
|
-
|
|
178
|
+
// ✅ CORRECT — respects visibility, enabled, stable
|
|
179
|
+
await page.getByRole('button', { name: 'Submit' }).click();
|
|
180
|
+
```
|
|
192
181
|
|
|
193
|
-
**
|
|
182
|
+
**Always include error path tests** — API 500, 404, network timeout, invalid input.
|
|
194
183
|
|
|
195
|
-
|
|
184
|
+
If the file exists → diff against test-plan, add only missing test cases.
|
|
196
185
|
|
|
197
|
-
|
|
186
|
+
### 6. Configure auth (if required)
|
|
198
187
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
188
|
+
- **API login**: Generate `auth.setup.ts` using `E2E_USERNAME`/`E2E_PASSWORD` + POST to login endpoint
|
|
189
|
+
- **UI login**: Generate `auth.setup.ts` using browser form fill. Update selectors to match your login page
|
|
190
|
+
- **Multi-user**: Separate `storageState` paths per role
|
|
191
|
+
|
|
192
|
+
**Credential format guidance**:
|
|
193
|
+
- If the app uses **email** for login → use `CHANGE_ME@example.com`
|
|
194
|
+
- If the app uses **username** (alphanumeric + underscore) → use `test_user_001` (more universal)
|
|
195
|
+
- Check existing test files or login page to determine the format
|
|
196
|
+
- Always set credentials via environment variables — never hardcode
|
|
202
197
|
|
|
203
|
-
|
|
198
|
+
**Prompt user**:
|
|
199
|
+
```
|
|
200
|
+
Auth required. To set up:
|
|
201
|
+
1. Customize tests/playwright/credentials.yaml
|
|
204
202
|
2. Export: export E2E_USERNAME=xxx E2E_PASSWORD=yyy
|
|
205
203
|
3. Run auth: npx playwright test --project=setup
|
|
206
|
-
4.
|
|
204
|
+
4. Re-run /opsx:e2e to execute tests
|
|
207
205
|
```
|
|
208
206
|
|
|
209
207
|
**Idempotency**: If `auth.setup.ts` already exists → verify format, update only if stale.
|
|
210
208
|
|
|
211
|
-
### 7. Configure playwright.config.ts
|
|
209
|
+
### 7. Configure playwright.config.ts
|
|
212
210
|
|
|
213
|
-
If
|
|
214
|
-
- **BASE_URL**: from `process.env.BASE_URL`, falling back to `tests/playwright/seed.spec.ts` → `BASE_URL` value, then `http://localhost:3000`
|
|
215
|
-
- **Dev command**: from `package.json` → scripts in order: `dev` → `start` → `serve` → `preview` → `npm run dev`
|
|
211
|
+
If missing → generate from `openspec/schemas/playwright-e2e/templates/playwright.config.ts`.
|
|
216
212
|
|
|
217
|
-
|
|
213
|
+
**Auto-detect BASE_URL** (in priority order):
|
|
214
|
+
1. `process.env.BASE_URL` if already set
|
|
215
|
+
2. `tests/playwright/seed.spec.ts` → extract `BASE_URL` value
|
|
216
|
+
3. Read `vite.config.ts` (or `vite.config.js`) → extract `server.port` + infer protocol (`https` if `server.https`, else `http`)
|
|
217
|
+
4. Read `package.json` → `scripts.dev` or `scripts.start` → extract port from `--port` flag
|
|
218
|
+
5. Fallback: `http://localhost:3000`
|
|
218
219
|
|
|
219
|
-
|
|
220
|
+
**Auto-detect dev command**:
|
|
221
|
+
1. `package.json` → scripts in order: `dev` → `start` → `serve` → `preview` → `npm run dev`
|
|
220
222
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
223
|
+
If playwright.config.ts exists → READ first, preserve ALL existing fields, add only missing `webServer` block.
|
|
224
|
+
|
|
225
|
+
### 8. Execute tests
|
|
224
226
|
|
|
225
|
-
**For role-based tests using `@tag`** (recommended over `--project` filtering):
|
|
226
227
|
```bash
|
|
227
|
-
|
|
228
|
+
openspec-pw run <name> --project=<role>
|
|
228
229
|
```
|
|
229
|
-
The `--project` approach runs ALL tests under each project's credentials — use `@tag` with `--grep` for precise filtering.
|
|
230
230
|
|
|
231
|
-
The CLI handles:
|
|
232
|
-
- Server lifecycle (start → wait for HTTP → test → stop)
|
|
233
|
-
- Port mismatch detection
|
|
234
|
-
- Report generation at `openspec/reports/playwright-e2e-<name>-<timestamp>.md`
|
|
231
|
+
The CLI handles: server lifecycle, port mismatch, report generation.
|
|
235
232
|
|
|
236
|
-
If tests fail →
|
|
233
|
+
If tests fail → use Playwright MCP tools to inspect UI, fix selectors, re-run.
|
|
237
234
|
|
|
238
235
|
**Healer MCP tools** (in order of use):
|
|
239
236
|
<!-- MCP_VERSION: 0.0.68 -->
|
|
@@ -247,77 +244,44 @@ If tests fail → analyze failures, use **Playwright MCP tools** to inspect UI s
|
|
|
247
244
|
| `browser_run_code` | Execute custom fix logic (optional) |
|
|
248
245
|
|
|
249
246
|
**Healer workflow**:
|
|
250
|
-
1. Read the failing test → identify failure type
|
|
251
|
-
2. Classify
|
|
247
|
+
1. Read the failing test → identify failure type
|
|
248
|
+
2. Classify:
|
|
252
249
|
|
|
253
250
|
| Failure type | Signal | Action |
|
|
254
251
|
|-------------|--------|--------|
|
|
255
|
-
| **Network/backend** | `fetch failed`, `net::ERR`, 5xx
|
|
256
|
-
| **Selector changed** | Element not found
|
|
257
|
-
| **Assertion mismatch** |
|
|
258
|
-
| **Timing issue** | `waitFor` timeout
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
- Re-run: `openspec-pw run <name> --project=<role>`
|
|
263
|
-
|
|
264
|
-
4. **After 3 failed attempts**, collect evidence:
|
|
252
|
+
| **Network/backend** | `fetch failed`, `net::ERR`, 5xx | `browser_console_messages` → `test.skip()` |
|
|
253
|
+
| **Selector changed** | Element not found | `browser_snapshot` → fix selector → re-run |
|
|
254
|
+
| **Assertion mismatch** | Wrong content/value | `browser_snapshot` → compare → fix assertion → re-run |
|
|
255
|
+
| **Timing issue** | `waitFor`/`page.evaluate` timeout | Switch to `request` API or add `waitFor` → re-run |
|
|
256
|
+
| **Wrong API usage** | `ctx.close is not a function` | Fix: `browser.newContext()` → `close()`; `request.newContext()` → no cleanup needed |
|
|
257
|
+
| **Auth expired** | 401 Unauthorized | Token may have expired — if long suite, recommend splitting or re-auth |
|
|
258
|
+
| **page.evaluate failure** | `fetch` in browser context, CORS errors | Switch to `page.request` API → re-run |
|
|
265
259
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|-------|--------|----------|
|
|
269
|
-
| `browser_console_messages` | ERROR-level messages present | App bug → `test.skip()` + report "console error" |
|
|
270
|
-
| `browser_snapshot` | Target element missing from DOM | App bug → `test.skip()` + report "element missing" |
|
|
271
|
-
| `browser_snapshot` | Element exists, no errors | Test bug → report recommendation |
|
|
272
|
-
|
|
273
|
-
- **App bug**: `test.skip('app bug — reason: <signal>')` + detailed report entry
|
|
274
|
-
- **Test bug**: report with "likely selector change, verify manually at file:line"
|
|
275
|
-
- Do NOT retry after evidence checklist — evidence is conclusive
|
|
260
|
+
3. **Attempt heal** (≤3 times): snapshot → fix → re-run
|
|
261
|
+
4. **After 3 failures**: collect evidence checklist → `test.skip()` if app bug, report recommendation if test bug
|
|
276
262
|
|
|
277
263
|
### 9. False Pass Detection
|
|
278
264
|
|
|
279
|
-
Run
|
|
265
|
+
Run after test suite completes (even if all pass):
|
|
280
266
|
|
|
281
|
-
**
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
if (await locator.isVisible().catch(() => false)) { ... }
|
|
285
|
-
```
|
|
286
|
-
→ If test passes, the locator might not exist → check with `browser_snapshot`
|
|
287
|
-
→ Report: "Test passed but may have skipped — conditional visibility check detected"
|
|
288
|
-
|
|
289
|
-
**Indicator B — Test ran too fast:**
|
|
290
|
-
A test covering a complex flow that completes in < 200ms is suspicious.
|
|
291
|
-
→ Inspect with `browser_snapshot` to confirm page state
|
|
292
|
-
→ Report: "Test duration suspiciously short — verify test logic was executed"
|
|
293
|
-
|
|
294
|
-
**Indicator C — Auth guard not tested:**
|
|
295
|
-
If specs mention "protected route" or "redirect to login" but no test uses a fresh browser context:
|
|
296
|
-
→ Report: "Auth guard not verified — test uses authenticated context (cookies/storage inherited)"
|
|
297
|
-
→ Recommendation: Add a test with `browser.newContext()` (no storageState) to verify the guard
|
|
267
|
+
- **Conditional logic**: Look for `if (locator.isVisible().catch(() => false))` — if test passes, locator may not exist
|
|
268
|
+
- **Too fast**: < 200ms for a complex flow is suspicious
|
|
269
|
+
- **No fresh auth context**: Protected routes without `browser.newContext()`
|
|
298
270
|
|
|
299
|
-
|
|
271
|
+
Report any gaps in a **⚠️ Coverage Gap** section.
|
|
300
272
|
|
|
301
273
|
### 10. Report results
|
|
302
274
|
|
|
303
|
-
Read
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
-
|
|
307
|
-
- Any auto-heal notes
|
|
308
|
-
- Recommendations for failed tests (with specific `file:line` references)
|
|
309
|
-
|
|
310
|
-
**Update tasks.md** (if all tests pass):
|
|
311
|
-
- Read `openspec/changes/<name>/tasks.md`
|
|
312
|
-
- Find tasks related to E2E testing (look for `[ ]` items mentioning "test", "e2e", "playwright", "verify")
|
|
313
|
-
- Append a verification note: e.g. `✅ Verified via Playwright E2E (<timestamp>)`
|
|
314
|
-
- Write the updated content back using the Edit tool
|
|
275
|
+
Read report at `openspec/reports/playwright-e2e-<name>-<timestamp>.md`. Present:
|
|
276
|
+
- Summary table (tests, passed, failed, duration, status)
|
|
277
|
+
- Auto-heal notes
|
|
278
|
+
- Recommendations with `file:line` references
|
|
315
279
|
|
|
316
|
-
|
|
280
|
+
**Update tasks.md** if all tests pass: find E2E-related items, append `✅ Verified via Playwright E2E (<timestamp>)`.
|
|
317
281
|
|
|
318
|
-
|
|
282
|
+
## Report Structure
|
|
319
283
|
|
|
320
|
-
```
|
|
284
|
+
```markdown
|
|
321
285
|
# Playwright E2E Report — <name>
|
|
322
286
|
|
|
323
287
|
## Summary
|
|
@@ -326,7 +290,6 @@ Read the report at `openspec/reports/playwright-e2e-<name>-<timestamp>.md`.
|
|
|
326
290
|
| N | N | N | Xm Xs | ✅/❌ |
|
|
327
291
|
|
|
328
292
|
## Results
|
|
329
|
-
|
|
330
293
|
### Passed
|
|
331
294
|
| Test | Duration | Notes |
|
|
332
295
|
|------|----------|-------|
|
|
@@ -345,49 +308,35 @@ Read the report at `openspec/reports/playwright-e2e-<name>-<timestamp>.md`.
|
|
|
345
308
|
- [ ] Requirement 2 (unverified)
|
|
346
309
|
|
|
347
310
|
## ⚠️ Coverage Gaps
|
|
348
|
-
> Tests passed but coverage gaps
|
|
311
|
+
> Tests passed but coverage gaps detected.
|
|
349
312
|
|
|
350
313
|
| Test | Gap | Recommendation |
|
|
351
314
|
|------|-----|----------------|
|
|
352
|
-
| ... | Conditional visibility check
|
|
353
|
-
| ... | Auth guard uses inherited session | Add fresh context test
|
|
354
|
-
| ... | Suspiciously fast execution (<200ms) | Verify test logic
|
|
355
|
-
|
|
356
|
-
### Updated tasks.md
|
|
357
|
-
```
|
|
358
|
-
- [x] Implement feature X ✅ Verified via Playwright E2E (2026-03-28)
|
|
315
|
+
| ... | Conditional visibility check | file:line — use `expect().toBeVisible()` |
|
|
316
|
+
| ... | Auth guard uses inherited session | Add fresh context test |
|
|
317
|
+
| ... | Suspiciously fast execution (<200ms) | Verify test logic executed |
|
|
359
318
|
```
|
|
360
319
|
|
|
361
320
|
## Graceful Degradation
|
|
362
321
|
|
|
363
322
|
| Scenario | Behavior |
|
|
364
323
|
|----------|----------|
|
|
365
|
-
| No specs
|
|
366
|
-
| Seed test fails | Stop
|
|
367
|
-
| No auth required | Skip auth setup
|
|
368
|
-
| test-plan.md exists | Read and use
|
|
369
|
-
| auth.setup.ts exists | Verify format
|
|
370
|
-
| playwright.config.ts exists |
|
|
371
|
-
| Test fails (
|
|
372
|
-
| Test fails (selector) | Healer: snapshot → fix
|
|
373
|
-
|
|
|
374
|
-
|
|
|
375
|
-
| False pass detected | Report coverage gap → add to "⚠️ Coverage Gap" section in report |
|
|
376
|
-
|
|
377
|
-
## Verification Heuristics
|
|
378
|
-
|
|
379
|
-
- **Coverage**: Every functional requirement → at least one test
|
|
380
|
-
- **Selector robustness**: Prefer `data-testid`, fallback to semantic selectors
|
|
381
|
-
- **False positives**: If test fails due to test bug (not app bug) → fix the test
|
|
382
|
-
- **Actionability**: Every failed test needs a specific recommendation
|
|
383
|
-
- **No false passes**: Every passing test must actually execute its test logic — verify absence of `if (isVisible())` conditional patterns
|
|
384
|
-
- **Auth guard verified**: Protected routes must have a test using a fresh browser context (no inherited cookies)
|
|
324
|
+
| No specs | Stop — E2E requires specs |
|
|
325
|
+
| Seed test fails | Stop — fix environment |
|
|
326
|
+
| No auth required | Skip auth setup |
|
|
327
|
+
| test-plan.md exists | Read and use (never regenerate) |
|
|
328
|
+
| auth.setup.ts exists | Verify format (update only if stale) |
|
|
329
|
+
| playwright.config.ts exists | Preserve all fields (add only missing) |
|
|
330
|
+
| Test fails (backend) | `test.skip()` + report |
|
|
331
|
+
| Test fails (selector/assertion) | Healer: snapshot → fix → re-run (≤3) |
|
|
332
|
+
| 3 heals failed | Evidence checklist → app bug: `test.skip()`; unclear: report |
|
|
333
|
+
| False pass detected | Add "⚠️ Coverage Gap" to report |
|
|
385
334
|
|
|
386
335
|
## Guardrails
|
|
387
336
|
|
|
388
337
|
- Read specs from `openspec/changes/<name>/specs/` as source of truth
|
|
389
338
|
- Do NOT generate tests that contradict the specs
|
|
390
|
-
- **DO generate real, runnable Playwright test code** — not placeholders or
|
|
391
|
-
- Do NOT overwrite files outside: `specs/playwright/`, `tests/playwright/`, `openspec/reports/`, `playwright.config.ts
|
|
339
|
+
- **DO generate real, runnable Playwright test code** — not placeholders or TODOs
|
|
340
|
+
- Do NOT overwrite files outside: `specs/playwright/`, `tests/playwright/`, `openspec/reports/`, `playwright.config.ts`
|
|
392
341
|
- Cap auto-heal at 3 attempts
|
|
393
342
|
- If no change specified → always ask user to select
|
|
@@ -20,6 +20,7 @@ export interface EditorAdapter {
|
|
|
20
20
|
}
|
|
21
21
|
/** Claude Code: .claude/commands/opsx/<id>.md + SKILL.md */
|
|
22
22
|
declare const claudeAdapter: EditorAdapter;
|
|
23
|
+
declare const ALL_ADAPTERS: EditorAdapter[];
|
|
23
24
|
/** Detect which editors are installed by checking their config directories */
|
|
24
25
|
export declare function detectEditors(projectRoot: string): EditorAdapter[];
|
|
25
26
|
/** Detect Codex by checking if CODEX_HOME or ~/.codex exists */
|
|
@@ -30,4 +31,8 @@ export declare function buildCommandMeta(body: string): CommandMeta;
|
|
|
30
31
|
export declare function installForAllEditors(body: string, adapters: EditorAdapter[], projectRoot: string): void;
|
|
31
32
|
/** Install SKILL.md only for Claude Code */
|
|
32
33
|
export declare function installSkill(projectRoot: string, skillContent: string): void;
|
|
33
|
-
|
|
34
|
+
/** Install project-level CLAUDE.md with employee-grade standards + OpenSpec context */
|
|
35
|
+
export declare function installProjectClaudeMd(projectRoot: string, standardsContent: string): void;
|
|
36
|
+
/** Read the employee-grade standards from a source file */
|
|
37
|
+
export declare function readEmployeeStandards(srcPath: string): string;
|
|
38
|
+
export { claudeAdapter, ALL_ADAPTERS };
|
package/dist/commands/editors.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
2
2
|
import { homedir } from 'os';
|
|
3
3
|
import { join, dirname } from 'path';
|
|
4
4
|
import chalk from 'chalk';
|
|
@@ -486,5 +486,35 @@ export function installSkill(projectRoot, skillContent) {
|
|
|
486
486
|
writeFileSync(join(skillDir, 'SKILL.md'), skillContent);
|
|
487
487
|
console.log(chalk.green(` ✓ claude: .claude/skills/openspec-e2e/SKILL.md`));
|
|
488
488
|
}
|
|
489
|
-
|
|
489
|
+
/** Install project-level CLAUDE.md with employee-grade standards + OpenSpec context */
|
|
490
|
+
export function installProjectClaudeMd(projectRoot, standardsContent) {
|
|
491
|
+
const dest = join(projectRoot, 'CLAUDE.md');
|
|
492
|
+
const exists = existsSync(dest);
|
|
493
|
+
if (exists) {
|
|
494
|
+
// Append standards inside OPENSPEC:START/END markers
|
|
495
|
+
const existing = readFileSync(dest, 'utf-8');
|
|
496
|
+
const markerStart = '<!-- OPENSPEC:START -->';
|
|
497
|
+
const markerEnd = '<!-- OPENSPEC:END -->';
|
|
498
|
+
if (existing.includes(markerStart) && existing.includes(markerEnd)) {
|
|
499
|
+
// Already has markers, skip
|
|
500
|
+
console.log(chalk.gray(' - CLAUDE.md already has standards markers, skipping'));
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
const updated = existing.trim() + '\n\n' + markerStart + '\n\n' + standardsContent + '\n\n' + markerEnd + '\n';
|
|
504
|
+
writeFileSync(dest, updated);
|
|
505
|
+
console.log(chalk.green(' ✓ CLAUDE.md: appended employee-grade standards'));
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
// No existing CLAUDE.md, create from template
|
|
510
|
+
const content = `# ${projectRoot.split('/').pop()}\n\n` + standardsContent;
|
|
511
|
+
writeFileSync(dest, content);
|
|
512
|
+
console.log(chalk.green(' ✓ CLAUDE.md: created with employee-grade standards'));
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
/** Read the employee-grade standards from a source file */
|
|
516
|
+
export function readEmployeeStandards(srcPath) {
|
|
517
|
+
return existsSync(srcPath) ? readFileSync(srcPath, 'utf-8') : '';
|
|
518
|
+
}
|
|
519
|
+
export { claudeAdapter, ALL_ADAPTERS };
|
|
490
520
|
//# sourceMappingURL=editors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editors.js","sourceRoot":"","sources":["../../src/commands/editors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,2DAA2D;AAC3D,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,YAAY,GAAG,kCAAkC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpE,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACxF,OAAO,IAAI,OAAO,GAAG,CAAC;IACxB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAC7D,CAAC;AAED,4DAA4D;AAC5D,SAAS,eAAe,CAAC,IAAc;IACrC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAChC,CAAC;AAED,8CAA8C;AAC9C,SAAS,yBAAyB,CAAC,IAAY;IAC7C,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAoBD,iFAAiF;AAEjF,4DAA4D;AAC5D,MAAM,aAAa,GAAkB;IACnC,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,IAAI;IACd,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9E,aAAa,CAAC,IAAI;QAChB,OAAO;QACH,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;eACnB,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC;YACpC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC;QAClC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAGhC,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,+EAA+E;AAE/E,4CAA4C;AAC5C,MAAM,aAAa,GAAkB;IACnC,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3E,aAAa,CAAC,IAAI;QAChB,OAAO;cACG,IAAI,CAAC,EAAE;WACV,IAAI,CAAC,EAAE;YACN,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC;eAC3B,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC;;;EAG9C,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,gFAAgF;AAEhF,iDAAiD;AACjD,MAAM,eAAe,GAAkB;IACrC,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9E,aAAa,CAAC,IAAI;QAChB,OAAO;QACH,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;eACnB,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC;YACpC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC;QAClC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAGhC,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,+EAA+E;AAE/E,uEAAuE;AACvE,MAAM,YAAY,GAAkB;IAClC,MAAM,EAAE,OAAO;IACf,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAChF,aAAa,CAAC,IAAI;QAChB,OAAO,KAAK,IAAI,CAAC,IAAI;;EAEvB,IAAI,CAAC,WAAW;;EAEhB,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,gFAAgF;AAEhF,mDAAmD;AACnD,MAAM,eAAe,GAAkB;IACrC,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IAChF,aAAa,CAAC,IAAI;QAChB,OAAO;aACE,IAAI,CAAC,EAAE;eACL,IAAI,CAAC,WAAW;;;;EAI7B,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,6EAA6E;AAE7E,8CAA8C;AAC9C,MAAM,cAAc,GAAkB;IACpC,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3E,aAAa,CAAC,IAAI;QAChB,OAAO;eACI,IAAI,CAAC,WAAW;;;EAG7B,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,6EAA6E;AAE7E,iDAAiD;AACjD,MAAM,kBAAkB,GAAkB;IACxC,MAAM,EAAE,aAAa;IACrB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3E,aAAa,CAAC,IAAI;QAChB,OAAO;eACI,IAAI,CAAC,WAAW;;;EAG7B,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,8EAA8E;AAE9E,6CAA6C;AAC7C,MAAM,aAAa,GAAkB;IACnC,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5E,aAAa,CAAC,IAAI;QAChB,OAAO;eACI,IAAI,CAAC,WAAW;;;;EAI7B,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,8EAA8E;AAE9E,kDAAkD;AAClD,MAAM,gBAAgB,GAAkB;IACtC,MAAM,EAAE,WAAW;IACnB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACjF,aAAa,CAAC,IAAI;QAChB,OAAO;QACH,IAAI,CAAC,IAAI;gBACD,IAAI,CAAC,WAAW;;;;EAI9B,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,6EAA6E;AAE7E,8DAA8D;AAC9D,MAAM,YAAY,GAAkB;IAClC,MAAM,EAAE,OAAO;IACf,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE;QACf,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC9E,OAAO,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IACD,aAAa,CAAC,IAAI;QAChB,OAAO;eACI,IAAI,CAAC,WAAW;;;;EAI7B,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,6EAA6E;AAE7E,uDAAuD;AACvD,MAAM,eAAe,GAAkB;IACrC,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACvF,aAAa,CAAC,IAAI;QAChB,OAAO;gBACK,IAAI,CAAC,WAAW;;;;EAI9B,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,6EAA6E;AAE7E,oEAAoE;AACpE,MAAM,YAAY,GAAkB;IAClC,MAAM,EAAE,OAAO;IACf,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7E,aAAa,CAAC,IAAI;QAChB,OAAO;QACH,IAAI,CAAC,IAAI;eACF,IAAI,CAAC,WAAW;YACnB,IAAI,CAAC,QAAQ;QACjB,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAGhC,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,8EAA8E;AAE9E,oDAAoD;AACpD,MAAM,cAAc,GAAkB;IACpC,MAAM,EAAE,SAAS;IACjB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5E,aAAa,CAAC,IAAI;QAChB,OAAO;eACI,IAAI,CAAC,WAAW;;;;EAI7B,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,8EAA8E;AAE9E,kDAAkD;AAClD,MAAM,aAAa,GAAkB;IACnC,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAChF,aAAa,CAAC,IAAI;QAChB,OAAO,kBAAkB,IAAI,CAAC,WAAW;;;EAG3C,IAAI,CAAC,IAAI;;CAEV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,8EAA8E;AAE9E,0DAA0D;AAC1D,MAAM,oBAAoB,GAAkB;IAC1C,MAAM,EAAE,gBAAgB;IACxB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IACjF,aAAa,CAAC,IAAI;QAChB,OAAO;eACI,IAAI,CAAC,WAAW;;;EAG7B,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,6EAA6E;AAE7E,0CAA0C;AAC1C,MAAM,YAAY,GAAkB;IAClC,MAAM,EAAE,OAAO;IACf,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1E,aAAa,CAAC,IAAI;QAChB,OAAO;cACG,IAAI,CAAC,EAAE;WACV,IAAI,CAAC,EAAE;YACN,IAAI,CAAC,QAAQ;eACV,IAAI,CAAC,WAAW;;;EAG7B,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,4EAA4E;AAE5E,8DAA8D;AAC9D,MAAM,eAAe,GAAkB;IACrC,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9E,aAAa,CAAC,IAAI;QAChB,OAAO,GAAG,IAAI,CAAC,IAAI;CACtB,CAAC;IACA,CAAC;CACF,CAAC;AAEF,6EAA6E;AAE7E,8CAA8C;AAC9C,MAAM,WAAW,GAAkB;IACjC,MAAM,EAAE,MAAM;IACd,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/E,aAAa,CAAC,IAAI;QAChB,OAAO;eACI,IAAI,CAAC,WAAW;;;EAG7B,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,6EAA6E;AAE7E,8EAA8E;AAC9E,MAAM,eAAe,GAAkB;IACrC,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7E,aAAa,CAAC,IAAI;QAChB,MAAM,WAAW,GAAG,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzD,OAAO;eACI,IAAI,CAAC,WAAW;;;EAG7B,WAAW;CACZ,CAAC;IACA,CAAC;CACF,CAAC;AAEF,4EAA4E;AAE5E,mCAAmC;AACnC,MAAM,SAAS,GAAkB;IAC/B,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACtE,aAAa,CAAC,IAAI;QAChB,OAAO;eACI,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC;;;EAG9C,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,6EAA6E;AAE7E,oEAAoE;AACpE,MAAM,YAAY,GAAkB;IAClC,MAAM,EAAE,OAAO;IACf,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7E,aAAa,CAAC,IAAI;QAChB,OAAO;QACH,IAAI,CAAC,IAAI;eACF,IAAI,CAAC,WAAW;YACnB,IAAI,CAAC,QAAQ;QACjB,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAGhC,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,4EAA4E;AAE5E,+CAA+C;AAC/C,MAAM,WAAW,GAAkB;IACjC,MAAM,EAAE,MAAM;IACd,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3E,aAAa,CAAC,IAAI;QAChB,OAAO,kBAAkB,IAAI,CAAC,WAAW;;;EAG3C,IAAI,CAAC,IAAI;;CAEV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,4EAA4E;AAE5E,4DAA4D;AAC5D,MAAM,cAAc,GAAkB;IACpC,MAAM,EAAE,SAAS;IACjB,QAAQ,EAAE,KAAK;IACf,cAAc,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACxE,aAAa,CAAC,IAAI;QAChB,OAAO,KAAK,IAAI,CAAC,IAAI;;EAEvB,IAAI,CAAC,WAAW;;EAEhB,IAAI,CAAC,IAAI;CACV,CAAC;IACA,CAAC;CACF,CAAC;AAEF,4EAA4E;AAE5E,MAAM,YAAY,GAAoB;IACpC,aAAa;IACb,aAAa;IACb,eAAe;IACf,YAAY;IACZ,eAAe;IACf,cAAc;IACd,kBAAkB;IAClB,aAAa;IACb,gBAAgB;IAChB,YAAY;IACZ,eAAe;IACf,YAAY;IACZ,cAAc;IACd,aAAa;IACb,oBAAoB;IACpB,YAAY;IACZ,eAAe;IACf,WAAW;IACX,eAAe;IACf,SAAS;IACT,YAAY;IACZ,WAAW;IACX,cAAc;CACf,CAAC;AAEF,8EAA8E;AAC9E,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,MAAM,MAAM,GAAmC;QAC7C,CAAC,SAAS,EAAE,aAAa,CAAC;QAC1B,CAAC,SAAS,EAAE,aAAa,CAAC;QAC1B,CAAC,WAAW,EAAE,eAAe,CAAC;QAC9B,CAAC,aAAa,EAAE,YAAY,CAAC;QAC7B,CAAC,WAAW,EAAE,eAAe,CAAC;QAC9B,CAAC,UAAU,EAAE,cAAc,CAAC;QAC5B,CAAC,QAAQ,EAAE,kBAAkB,CAAC;QAC9B,CAAC,UAAU,EAAE,aAAa,CAAC;QAC3B,CAAC,YAAY,EAAE,gBAAgB,CAAC;QAChC,CAAC,SAAS,EAAE,eAAe,CAAC;QAC5B,CAAC,QAAQ,EAAE,YAAY,CAAC;QACxB,CAAC,UAAU,EAAE,cAAc,CAAC;QAC5B,CAAC,SAAS,EAAE,aAAa,CAAC;QAC1B,CAAC,SAAS,EAAE,oBAAoB,CAAC;QACjC,CAAC,QAAQ,EAAE,YAAY,CAAC;QACxB,CAAC,WAAW,EAAE,eAAe,CAAC;QAC9B,CAAC,OAAO,EAAE,WAAW,CAAC;QACtB,CAAC,WAAW,EAAE,eAAe,CAAC;QAC9B,CAAC,KAAK,EAAE,SAAS,CAAC;QAClB,CAAC,QAAQ,EAAE,YAAY,CAAC;QACxB,CAAC,OAAO,EAAE,WAAW,CAAC;QACtB,CAAC,MAAM,EAAE,cAAc,CAAC;KACzB,CAAC;IAEF,OAAO,MAAM;SACV,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC;SACrD,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC;AAED,4EAA4E;AAE5E,gEAAgE;AAChE,MAAM,UAAU,WAAW;IACzB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC9E,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AACrD,CAAC;AAED,8EAA8E;AAE9E,wCAAwC;AACxC,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO;QACL,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,wDAAwD;QACrE,QAAQ,EAAE,UAAU;QACpB,IAAI,EAAE,CAAC,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,CAAC;QAClD,IAAI;KACL,CAAC;AACJ,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,QAAyB,EACzB,WAAmB;IAEnB,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAEpC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChD,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC3C,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,YAAY,CAAC,WAAmB,EAAE,YAAoB;IACpE,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;IACxE,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,YAAY,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"editors.js","sourceRoot":"","sources":["../../src/commands/editors.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/init.js
CHANGED
|
@@ -6,11 +6,12 @@ import { fileURLToPath } from 'url';
|
|
|
6
6
|
import chalk from 'chalk';
|
|
7
7
|
import { readFile } from 'fs/promises';
|
|
8
8
|
import { syncMcpTools } from './mcpSync.js';
|
|
9
|
-
import { detectEditors, detectCodex, installForAllEditors, installSkill, claudeAdapter } from './editors.js';
|
|
9
|
+
import { detectEditors, detectCodex, installForAllEditors, installSkill, installProjectClaudeMd, readEmployeeStandards, claudeAdapter } from './editors.js';
|
|
10
10
|
const TEMPLATE_DIR = fileURLToPath(new URL('../../templates', import.meta.url));
|
|
11
11
|
const SCHEMA_DIR = fileURLToPath(new URL('../../schemas', import.meta.url));
|
|
12
12
|
const SKILL_SRC = fileURLToPath(new URL('../../.claude/skills/openspec-e2e/SKILL.md', import.meta.url));
|
|
13
13
|
const CMD_BODY_SRC = fileURLToPath(new URL('../../.claude/commands/opsx/e2e-body.md', import.meta.url));
|
|
14
|
+
const EMPLOYEE_STANDARDS_SRC = fileURLToPath(new URL('../../employee-standards.md', import.meta.url));
|
|
14
15
|
export async function init(options) {
|
|
15
16
|
console.log(chalk.blue('\n🔧 OpenSpec + Playwright E2E Setup\n'));
|
|
16
17
|
const projectRoot = process.cwd();
|
|
@@ -98,7 +99,13 @@ export async function init(options) {
|
|
|
98
99
|
console.log(chalk.blue('\n─── Generating Seed Test ───'));
|
|
99
100
|
await generateSeedTest(projectRoot);
|
|
100
101
|
}
|
|
101
|
-
// 8.
|
|
102
|
+
// 8. Install employee-grade CLAUDE.md
|
|
103
|
+
console.log(chalk.blue('\n─── Installing Employee Standards ───'));
|
|
104
|
+
const standards = readEmployeeStandards(EMPLOYEE_STANDARDS_SRC);
|
|
105
|
+
if (standards) {
|
|
106
|
+
installProjectClaudeMd(projectRoot, standards);
|
|
107
|
+
}
|
|
108
|
+
// 9. Summary
|
|
102
109
|
console.log(chalk.blue('\n─── Summary ───'));
|
|
103
110
|
console.log(chalk.green(' ✓ Setup complete!\n'));
|
|
104
111
|
console.log(chalk.bold('Next steps:'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,UAAU,EACV,YAAY,EACZ,aAAa,EACb,SAAS,GACV,MAAM,IAAI,CAAC;AACZ,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,oBAAoB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,UAAU,EACV,YAAY,EACZ,aAAa,EACb,SAAS,GACV,MAAM,IAAI,CAAC;AACZ,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,oBAAoB,EAAE,YAAY,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE5J,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChF,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5E,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,4CAA4C,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACxG,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,yCAAyC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACxG,MAAM,sBAAsB,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,6BAA6B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAQtG,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAAoB;IAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC,CAAC;IAElE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAElC,yBAAyB;IACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAEjD,MAAM,OAAO,GAAG,OAAO,CAAC,gBAAgB,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,OAAO,CAAC,wDAAwD,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;IAExG,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC,CAAC;IAEtD,oBAAoB;IACpB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,yDAAyD,CAAC,CAAC,CAAC;QACrF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC,CAAC;QACjE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC,CAAC;QAChE,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC;IAErD,qCAAqC;IACrC,IAAI,OAAO,CAAC,GAAG,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC,CAAC;QAE/D,0DAA0D;QAC1D,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;QACvD,MAAM,UAAU,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvG,MAAM,SAAS,GAAG,UAAU,EAAE,UAAU,IAAI,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAG,UAAU,EAAE,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,UAAU,IAAI,EAAE,CAAC;QAEvE,IAAI,SAAS,CAAC,YAAY,CAAC,IAAI,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YACtD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC;gBACH,QAAQ,CAAC,sDAAsD,EAAE;oBAC/D,GAAG,EAAE,WAAW;oBAChB,KAAK,EAAE,SAAS;iBACjB,CAAC,CAAC;gBACH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC,CAAC;gBAClE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC,CAAC;YACjE,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,kCAAkC,CAAC,CAAC,CAAC;gBAC9D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC,CAAC;gBAChG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC,CAAC;YAChF,CAAC;QACH,CAAC;IACH,CAAC;IAED,+CAA+C;IAC/C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IACzD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACnD,oBAAoB,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;IACpD,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACnD,oBAAoB,CAAC,IAAI,EAAE,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC,CAAC;IAC3D,CAAC;IAED,qCAAqC;IACrC,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;QAC7C,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACxD,YAAY,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAC1C,CAAC;IAED,sEAAsE;IACtE,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC,CAAC;QAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC;QACrF,MAAM,YAAY,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC,CAAC;IAC7E,CAAC;IAED,6BAA6B;IAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC,CAAC;IAChE,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC;IAEjC,wBAAwB;IACxB,IAAI,OAAO,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC,CAAC;QAC1D,MAAM,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC;IAED,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC,CAAC;IACnE,MAAM,SAAS,GAAG,qBAAqB,CAAC,sBAAsB,CAAC,CAAC;IAChE,IAAI,SAAS,EAAE,CAAC;QACd,sBAAsB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IACjD,CAAC;IAED,aAAa;IACb,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAElD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC,CAAC;IAChG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC,CAAC;IAChG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gEAAgE,CAAC,CAAC,CAAC;IAC1F,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC,CAAC;IACpF,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;IAC3D,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,oCAAoC,CAAC,CAAC,CAAC;IAC1F,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,2CAA2C,CAAC,CAAC,CAAC;IAEjG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC,CAAC;IACrF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC,CAAC;IACvE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,WAAmB;IACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;IAC1D,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IAChD,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC,CAAC;IACvE,CAAC;SAAM,CAAC;QACN,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,YAAY,GAAG,eAAe,EAAE,OAAO,CAAC,CAAC;QAC5E,aAAa,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC,CAAC;IAC3E,CAAC;IAED,yBAAyB;IACzB,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IACtD,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC,CAAC;IACxE,CAAC;SAAM,CAAC;QACN,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,YAAY,GAAG,gBAAgB,EAAE,OAAO,CAAC,CAAC;QAC7E,aAAa,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,4BAA4B;IAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;IACrD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC,CAAC;IAC3E,CAAC;SAAM,CAAC;QACN,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,YAAY,GAAG,mBAAmB,EAAE,OAAO,CAAC,CAAC;QACjF,aAAa,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC,CAAC;IAC/E,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC,CAAC;AACjF,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,WAAmB;IAC9C,MAAM,SAAS,GAAG,UAAU,GAAG,iBAAiB,CAAC;IACjD,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAC9E,MAAM,WAAW,GAAG,CAAC,aAAa,CAAC,CAAC;IAEpC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACpC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,aAAa,CAAC,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,iBAAiB;IACjB,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAClD,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IACpD,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,CAAC,cAAc,EAAE,WAAW,EAAE,aAAa,EAAE,sBAAsB,CAAC,CAAC;IAC3F,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;QACvC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,aAAa,CAAC,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC,CAAC;AACrF,CAAC;AAED,SAAS,OAAO,CACd,GAAW,EACX,IAAY,EACZ,MAAM,GAAG,KAAK;IAEd,IAAI,CAAC;QACH,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,IAAI,QAAQ,CAAC,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,IAAI,YAAY,CAAC,CAAC,CAAC;QAChE,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Claude Code Employee-Grade Configuration
|
|
2
|
+
|
|
3
|
+
> 员工级行为规范,适用于所有项目。
|
|
4
|
+
> 本项目遵循 OpenSpec 规范驱动开发流程(详见 /openspec/)。
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 一、代码质量
|
|
9
|
+
|
|
10
|
+
### 强制验证
|
|
11
|
+
|
|
12
|
+
禁止在验证完成前报告成功。每次文件修改后必须运行:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx tsc --noEmit && npx eslint . --quiet
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
如项目无类型检查,明确告知用户,不得假装成功。
|
|
19
|
+
|
|
20
|
+
### 高级工程师标准
|
|
21
|
+
|
|
22
|
+
不接受"最简单方案"和"不超出需求"作为偷懒的借口。如果架构有缺陷、状态重复、模式不一致——说出来并修复。问自己:**高级工程师在 code review 中会拒绝什么?** 把那些全部修掉。
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 二、上下文管理
|
|
27
|
+
|
|
28
|
+
### Step 0 规则
|
|
29
|
+
|
|
30
|
+
任何结构性重构(>300 LOC)之前,先删除所有死代码(未使用 import/export/prop/console.log)。单独提交清理,再做重构。
|
|
31
|
+
死代码会提前消耗 token budget,触发 auto-compaction——每次失败会浪费大量 API 调用。保持代码干净直接节省成本。
|
|
32
|
+
|
|
33
|
+
### 文件读取分段
|
|
34
|
+
|
|
35
|
+
超过 500 行的文件,不要假设单次读取覆盖了完整文件。根据需要分次读取相关段落,或编辑前重新读取完整文件以确保上下文最新。
|
|
36
|
+
|
|
37
|
+
### 上下文衰减
|
|
38
|
+
|
|
39
|
+
超过 10 条消息后,编辑任何文件前必须重新读取。
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 三、大规模任务
|
|
44
|
+
|
|
45
|
+
### 子 Agent 并行化
|
|
46
|
+
|
|
47
|
+
任务涉及超过 5 个独立文件时,启动并行子 agent(每个 5-8 个文件),每个拥有独立 token budget。
|
|
48
|
+
|
|
49
|
+
### 分阶段执行
|
|
50
|
+
|
|
51
|
+
不要在单次响应中完成多文件重构。每个阶段不超过 5 个文件,完成后验证,等待用户批准再继续。
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 四、工具限制
|
|
56
|
+
|
|
57
|
+
### 工具结果截断(50,000 字符)
|
|
58
|
+
|
|
59
|
+
搜索结果异常少时,用更窄范围重新运行。怀疑截断时告知用户。
|
|
60
|
+
|
|
61
|
+
### Grep 不是 AST
|
|
62
|
+
|
|
63
|
+
重命名函数/类型/变量时,必须分开搜索:
|
|
64
|
+
|
|
65
|
+
- 直接调用和引用
|
|
66
|
+
- 类型级引用(interface、泛型)
|
|
67
|
+
- 字符串字面量(动态引用)
|
|
68
|
+
- `require()` / `import`
|
|
69
|
+
- barrel file 和 re-export
|
|
70
|
+
- 测试文件和 mock
|
|
71
|
+
|
|
72
|
+
不得假设一次 grep 覆盖所有情况。
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 五、编辑安全
|
|
77
|
+
|
|
78
|
+
### 编辑完整性
|
|
79
|
+
|
|
80
|
+
每次编辑前重新读取文件,编辑后再次读取确认变更正确应用。同一文件连续编辑不超过 3 次,中间必须验证读取。
|
|
81
|
+
|
|
82
|
+
### 变更完整性
|
|
83
|
+
|
|
84
|
+
重命名或签名变更完成后,明确告知用户可能遗漏的区域(动态引用、测试 mock 等),提示人工复查。
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openspec-playwright",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.44",
|
|
4
4
|
"description": "OpenSpec + Playwright E2E verification setup tool for Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc",
|
|
11
|
+
"test": "vitest",
|
|
12
|
+
"test:run": "vitest run",
|
|
11
13
|
"prepublishOnly": "npm run build",
|
|
12
14
|
"release": "npm version patch && npm run build && git push && git push --tags && npm publish"
|
|
13
15
|
},
|
|
@@ -18,7 +20,8 @@
|
|
|
18
20
|
},
|
|
19
21
|
"devDependencies": {
|
|
20
22
|
"@types/node": "^22.0.0",
|
|
21
|
-
"typescript": "^5.6.0"
|
|
23
|
+
"typescript": "^5.6.0",
|
|
24
|
+
"vitest": "^4.1.2"
|
|
22
25
|
},
|
|
23
26
|
"engines": {
|
|
24
27
|
"node": ">=20"
|
package/release-notes.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
## What's Changed
|
|
2
2
|
|
|
3
|
-
-
|
|
3
|
+
- feat(SKILL): add Playwright API guardrails and expand Healer decision tree
|
|
4
4
|
|
|
5
|
-
**Full Changelog**: https://github.com/wxhou/openspec-playwright/releases/tag/v0.1.
|
|
5
|
+
**Full Changelog**: https://github.com/wxhou/openspec-playwright/releases/tag/v0.1.44
|
package/src/commands/editors.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
2
2
|
import { homedir } from 'os';
|
|
3
3
|
import { join, dirname } from 'path';
|
|
4
4
|
import chalk from 'chalk';
|
|
@@ -570,4 +570,35 @@ export function installSkill(projectRoot: string, skillContent: string): void {
|
|
|
570
570
|
console.log(chalk.green(` ✓ claude: .claude/skills/openspec-e2e/SKILL.md`));
|
|
571
571
|
}
|
|
572
572
|
|
|
573
|
-
|
|
573
|
+
/** Install project-level CLAUDE.md with employee-grade standards + OpenSpec context */
|
|
574
|
+
export function installProjectClaudeMd(projectRoot: string, standardsContent: string): void {
|
|
575
|
+
const dest = join(projectRoot, 'CLAUDE.md');
|
|
576
|
+
const exists = existsSync(dest);
|
|
577
|
+
if (exists) {
|
|
578
|
+
// Append standards inside OPENSPEC:START/END markers
|
|
579
|
+
const existing = readFileSync(dest, 'utf-8');
|
|
580
|
+
const markerStart = '<!-- OPENSPEC:START -->';
|
|
581
|
+
const markerEnd = '<!-- OPENSPEC:END -->';
|
|
582
|
+
|
|
583
|
+
if (existing.includes(markerStart) && existing.includes(markerEnd)) {
|
|
584
|
+
// Already has markers, skip
|
|
585
|
+
console.log(chalk.gray(' - CLAUDE.md already has standards markers, skipping'));
|
|
586
|
+
} else {
|
|
587
|
+
const updated = existing.trim() + '\n\n' + markerStart + '\n\n' + standardsContent + '\n\n' + markerEnd + '\n';
|
|
588
|
+
writeFileSync(dest, updated);
|
|
589
|
+
console.log(chalk.green(' ✓ CLAUDE.md: appended employee-grade standards'));
|
|
590
|
+
}
|
|
591
|
+
} else {
|
|
592
|
+
// No existing CLAUDE.md, create from template
|
|
593
|
+
const content = `# ${projectRoot.split('/').pop()}\n\n` + standardsContent;
|
|
594
|
+
writeFileSync(dest, content);
|
|
595
|
+
console.log(chalk.green(' ✓ CLAUDE.md: created with employee-grade standards'));
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/** Read the employee-grade standards from a source file */
|
|
600
|
+
export function readEmployeeStandards(srcPath: string): string {
|
|
601
|
+
return existsSync(srcPath) ? readFileSync(srcPath, 'utf-8') : '';
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
export { claudeAdapter, ALL_ADAPTERS };
|
package/src/commands/init.ts
CHANGED
|
@@ -11,12 +11,13 @@ import { fileURLToPath } from 'url';
|
|
|
11
11
|
import chalk from 'chalk';
|
|
12
12
|
import { readFile } from 'fs/promises';
|
|
13
13
|
import { syncMcpTools } from './mcpSync.js';
|
|
14
|
-
import { detectEditors, detectCodex, installForAllEditors, installSkill, claudeAdapter } from './editors.js';
|
|
14
|
+
import { detectEditors, detectCodex, installForAllEditors, installSkill, installProjectClaudeMd, readEmployeeStandards, claudeAdapter } from './editors.js';
|
|
15
15
|
|
|
16
16
|
const TEMPLATE_DIR = fileURLToPath(new URL('../../templates', import.meta.url));
|
|
17
17
|
const SCHEMA_DIR = fileURLToPath(new URL('../../schemas', import.meta.url));
|
|
18
18
|
const SKILL_SRC = fileURLToPath(new URL('../../.claude/skills/openspec-e2e/SKILL.md', import.meta.url));
|
|
19
19
|
const CMD_BODY_SRC = fileURLToPath(new URL('../../.claude/commands/opsx/e2e-body.md', import.meta.url));
|
|
20
|
+
const EMPLOYEE_STANDARDS_SRC = fileURLToPath(new URL('../../employee-standards.md', import.meta.url));
|
|
20
21
|
|
|
21
22
|
export interface InitOptions {
|
|
22
23
|
change?: string;
|
|
@@ -121,7 +122,14 @@ export async function init(options: InitOptions) {
|
|
|
121
122
|
await generateSeedTest(projectRoot);
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
// 8.
|
|
125
|
+
// 8. Install employee-grade CLAUDE.md
|
|
126
|
+
console.log(chalk.blue('\n─── Installing Employee Standards ───'));
|
|
127
|
+
const standards = readEmployeeStandards(EMPLOYEE_STANDARDS_SRC);
|
|
128
|
+
if (standards) {
|
|
129
|
+
installProjectClaudeMd(projectRoot, standards);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 9. Summary
|
|
125
133
|
console.log(chalk.blue('\n─── Summary ───'));
|
|
126
134
|
console.log(chalk.green(' ✓ Setup complete!\n'));
|
|
127
135
|
|
package/templates/auth.setup.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
// For multi-user testing, add more setup blocks with different storageState paths.
|
|
14
14
|
|
|
15
15
|
import { test as setup, expect } from '@playwright/test';
|
|
16
|
+
import { existsSync } from 'fs';
|
|
16
17
|
|
|
17
18
|
// ─── API Login (preferred) ───────────────────────────────────────────────────
|
|
18
19
|
// If your app has a login API, configure it in tests/playwright/credentials.yaml:
|
|
@@ -25,8 +26,10 @@ setup('authenticate via API', async ({ page }) => {
|
|
|
25
26
|
const password = process.env.E2E_PASSWORD;
|
|
26
27
|
|
|
27
28
|
if (!username || !password) {
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
throw new Error(
|
|
30
|
+
'E2E_USERNAME and E2E_PASSWORD environment variables are required.\n' +
|
|
31
|
+
'Set them with: export E2E_USERNAME=xxx E2E_PASSWORD=yyy'
|
|
32
|
+
);
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
const res = await page.request.post(`${baseUrl}/api/auth/login`, {
|
|
@@ -38,6 +41,10 @@ setup('authenticate via API', async ({ page }) => {
|
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
await page.context().storageState({ path: './playwright/.auth/user.json' });
|
|
44
|
+
|
|
45
|
+
if (!existsSync('./playwright/.auth/user.json')) {
|
|
46
|
+
throw new Error('Auth setup failed: storageState file was not created');
|
|
47
|
+
}
|
|
41
48
|
});
|
|
42
49
|
|
|
43
50
|
// ─── UI Login (fallback) ─────────────────────────────────────────────────────
|
|
@@ -49,8 +56,10 @@ setup('authenticate via UI', async ({ page }) => {
|
|
|
49
56
|
const password = process.env.E2E_PASSWORD;
|
|
50
57
|
|
|
51
58
|
if (!username || !password) {
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
throw new Error(
|
|
60
|
+
'E2E_USERNAME and E2E_PASSWORD environment variables are required.\n' +
|
|
61
|
+
'Set them with: export E2E_USERNAME=xxx E2E_PASSWORD=yyy'
|
|
62
|
+
);
|
|
54
63
|
}
|
|
55
64
|
|
|
56
65
|
// TODO: Update these selectors to match your login page
|
|
@@ -74,4 +83,8 @@ setup('authenticate via UI', async ({ page }) => {
|
|
|
74
83
|
await expect(page).not.toHaveURL(/.*login.*|.*signin.*/);
|
|
75
84
|
|
|
76
85
|
await page.context().storageState({ path: './playwright/.auth/user.json' });
|
|
86
|
+
|
|
87
|
+
if (!existsSync('./playwright/.auth/user.json')) {
|
|
88
|
+
throw new Error('Auth setup failed: storageState file was not created');
|
|
89
|
+
}
|
|
77
90
|
});
|
|
@@ -21,13 +21,13 @@ api: /api/auth/login # Leave empty for UI login
|
|
|
21
21
|
|
|
22
22
|
users:
|
|
23
23
|
- name: user
|
|
24
|
-
username:
|
|
25
|
-
password:
|
|
24
|
+
username: CHANGE_ME@example.com
|
|
25
|
+
password: CHANGE_ME_PASSWORD
|
|
26
26
|
|
|
27
27
|
# Multi-user example (uncomment and configure for role-based tests):
|
|
28
28
|
# - name: admin
|
|
29
|
-
# username: admin
|
|
30
|
-
# password:
|
|
29
|
+
# username: CHANGE_ME@admin.com
|
|
30
|
+
# password: CHANGE_ME_ADMIN_PASSWORD
|
|
31
31
|
# - name: premium
|
|
32
|
-
# username: premium
|
|
33
|
-
# password:
|
|
32
|
+
# username: CHANGE_ME@premium.com
|
|
33
|
+
# password: CHANGE_ME_PREMIUM_PASSWORD
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
escapeYamlValue,
|
|
4
|
+
formatTagsArray,
|
|
5
|
+
buildCommandMeta,
|
|
6
|
+
detectEditors,
|
|
7
|
+
detectCodex,
|
|
8
|
+
ALL_ADAPTERS,
|
|
9
|
+
} from '../src/commands/editors.js';
|
|
10
|
+
|
|
11
|
+
// ─── escapeYamlValue ──────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
describe('escapeYamlValue', () => {
|
|
14
|
+
it('returns raw value for plain strings', () => {
|
|
15
|
+
expect(escapeYamlValue('hello world')).toBe('hello world');
|
|
16
|
+
expect(escapeYamlValue('simple')).toBe('simple');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('quotes strings with colons', () => {
|
|
20
|
+
expect(escapeYamlValue('hello: world')).toBe('"hello: world"');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('quotes strings starting with whitespace', () => {
|
|
24
|
+
expect(escapeYamlValue(' hello')).toBe('" hello"');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('quotes strings ending with whitespace', () => {
|
|
28
|
+
expect(escapeYamlValue('hello ')).toBe('"hello "');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('quotes and escapes strings containing quotes', () => {
|
|
32
|
+
expect(escapeYamlValue('say "hello"')).toBe('"say \\"hello\\""');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('quotes and escapes strings containing newlines', () => {
|
|
36
|
+
expect(escapeYamlValue('line1\nline2')).toBe('"line1\\nline2"');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('quotes strings with special YAML chars', () => {
|
|
40
|
+
expect(escapeYamlValue('key: value')).toBe('"key: value"');
|
|
41
|
+
expect(escapeYamlValue('# comment')).toBe('"# comment"');
|
|
42
|
+
expect(escapeYamlValue('a{b}c')).toBe('"a{b}c"');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('quotes strings with array-like chars', () => {
|
|
46
|
+
expect(escapeYamlValue('[a, b]')).toBe('"[a, b]"');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// ─── formatTagsArray ─────────────────────────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
describe('formatTagsArray', () => {
|
|
53
|
+
it('formats empty tags', () => {
|
|
54
|
+
expect(formatTagsArray([])).toBe('[]');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('formats single tag', () => {
|
|
58
|
+
expect(formatTagsArray(['openspec'])).toBe('[openspec]');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('formats multiple tags', () => {
|
|
62
|
+
expect(formatTagsArray(['openspec', 'playwright', 'e2e'])).toBe(
|
|
63
|
+
'[openspec, playwright, e2e]'
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('escapes tags with colons using YAML quoting', () => {
|
|
68
|
+
// escapeYamlValue quotes 'tag:colon' → "tag:colon", so array has quoted element
|
|
69
|
+
expect(formatTagsArray(['tag:colon'])).toBe('["tag:colon"]');
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// ─── buildCommandMeta ─────────────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
describe('buildCommandMeta', () => {
|
|
76
|
+
it('creates meta with correct id', () => {
|
|
77
|
+
const meta = buildCommandMeta('test body');
|
|
78
|
+
expect(meta.id).toBe('e2e');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('creates meta with correct fields', () => {
|
|
82
|
+
const meta = buildCommandMeta('test body');
|
|
83
|
+
expect(meta.name).toBe('OPSX: E2E');
|
|
84
|
+
expect(meta.description).toBe('Run Playwright E2E verification for an OpenSpec change');
|
|
85
|
+
expect(meta.category).toBe('OpenSpec');
|
|
86
|
+
expect(meta.tags).toEqual(['openspec', 'playwright', 'e2e', 'testing']);
|
|
87
|
+
expect(meta.body).toBe('test body');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// ─── detectEditors ────────────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
describe('detectEditors', () => {
|
|
94
|
+
it('returns empty array for non-existent directory', () => {
|
|
95
|
+
const result = detectEditors('/tmp/nonexistent-project-xyz-123');
|
|
96
|
+
expect(result).toEqual([]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('detects Claude Code when .claude directory exists', () => {
|
|
100
|
+
const result = detectEditors('/Users/wxhou/Documents/openspec-playwright');
|
|
101
|
+
const names = result.map(a => a.toolId);
|
|
102
|
+
expect(names).toContain('claude');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// ─── detectCodex ─────────────────────────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
describe('detectCodex', () => {
|
|
109
|
+
it('returns null when CODEX_HOME is set to non-existent path', () => {
|
|
110
|
+
const original = process.env.CODEX_HOME;
|
|
111
|
+
process.env.CODEX_HOME = '/tmp/this-codex-dir-does-not-exist-xyz';
|
|
112
|
+
const result = detectCodex();
|
|
113
|
+
expect(result).toBeNull();
|
|
114
|
+
if (original !== undefined) {
|
|
115
|
+
process.env.CODEX_HOME = original;
|
|
116
|
+
} else {
|
|
117
|
+
delete process.env.CODEX_HOME;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// ─── Adapter format correctness ───────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
describe('Adapter format correctness', () => {
|
|
125
|
+
it('every adapter has a toolId', () => {
|
|
126
|
+
for (const adapter of ALL_ADAPTERS) {
|
|
127
|
+
expect(adapter.toolId).toBeTruthy();
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('every adapter has formatCommand that returns non-empty string', () => {
|
|
132
|
+
const meta = buildCommandMeta('test body content');
|
|
133
|
+
for (const adapter of ALL_ADAPTERS) {
|
|
134
|
+
const output = adapter.formatCommand(meta);
|
|
135
|
+
expect(output.length).toBeGreaterThan(0);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('every adapter getCommandPath returns a path with the id', () => {
|
|
140
|
+
const meta = buildCommandMeta('test');
|
|
141
|
+
for (const adapter of ALL_ADAPTERS) {
|
|
142
|
+
const path = adapter.getCommandPath(meta.id);
|
|
143
|
+
expect(path).toContain('opsx');
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('Claude adapter output has YAML frontmatter', () => {
|
|
148
|
+
const meta = buildCommandMeta('body');
|
|
149
|
+
const output = ALL_ADAPTERS[0].formatCommand(meta);
|
|
150
|
+
expect(output).toContain('---');
|
|
151
|
+
expect(output).toContain('name:');
|
|
152
|
+
expect(output).toContain('description:');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('TOML adapters (gemini, qwen) do not use YAML frontmatter', () => {
|
|
156
|
+
const meta = buildCommandMeta('body');
|
|
157
|
+
const adapters = ALL_ADAPTERS.filter(
|
|
158
|
+
a => a.toolId === 'gemini' || a.toolId === 'qwen'
|
|
159
|
+
);
|
|
160
|
+
for (const adapter of adapters) {
|
|
161
|
+
const output = adapter.formatCommand(meta);
|
|
162
|
+
expect(output).not.toContain('---');
|
|
163
|
+
expect(output).toContain('description =');
|
|
164
|
+
expect(output).toContain('prompt =');
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('crush and qoder use raw values without escaping in name/description', () => {
|
|
169
|
+
const meta = buildCommandMeta('body');
|
|
170
|
+
const adapters = ALL_ADAPTERS.filter(
|
|
171
|
+
a => a.toolId === 'crush' || a.toolId === 'qoder'
|
|
172
|
+
);
|
|
173
|
+
for (const adapter of adapters) {
|
|
174
|
+
const output = adapter.formatCommand(meta);
|
|
175
|
+
// Should NOT have escaped quotes in the raw-value fields
|
|
176
|
+
expect(output).not.toContain('\\\\"');
|
|
177
|
+
expect(output).toContain('name: OPSX: E2E');
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|
package/vitest.config.ts
ADDED
|
Binary file
|