openspec-playwright 0.1.62 → 0.1.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +4 -3
  3. package/README.zh-CN.md +4 -3
  4. package/bin/CLAUDE.md +11 -0
  5. package/dist/CLAUDE.md +17 -0
  6. package/dist/commands/doctor.d.ts +4 -1
  7. package/dist/commands/doctor.js +110 -73
  8. package/dist/commands/doctor.js.map +1 -1
  9. package/dist/commands/editors.js +149 -95
  10. package/dist/commands/editors.js.map +1 -1
  11. package/dist/commands/init.js +105 -97
  12. package/dist/commands/init.js.map +1 -1
  13. package/dist/commands/mcpSync.js +46 -31
  14. package/dist/commands/mcpSync.js.map +1 -1
  15. package/dist/commands/run.d.ts +13 -0
  16. package/dist/commands/run.js +74 -51
  17. package/dist/commands/run.js.map +1 -1
  18. package/dist/commands/uninstall.d.ts +1 -0
  19. package/dist/commands/uninstall.js +133 -0
  20. package/dist/commands/uninstall.js.map +1 -0
  21. package/dist/commands/update.js +79 -68
  22. package/dist/commands/update.js.map +1 -1
  23. package/dist/index.js +33 -26
  24. package/dist/index.js.map +1 -1
  25. package/package.json +19 -1
  26. package/schemas/playwright-e2e/templates/playwright.config.ts +22 -22
  27. package/templates/CLAUDE.md +15 -0
  28. package/templates/seed.spec.ts +5 -3
  29. package/.claude/commands/opsx/e2e-body.md +0 -39
  30. package/.claude/commands/opsx/e2e.md +0 -47
  31. package/.claude/skills/openspec-e2e/SKILL.md +0 -464
  32. package/.github/workflows/release.yml +0 -81
  33. package/docs/plans/2026-03-26-openspec-playwright-design.md +0 -180
  34. package/employee-standards.md +0 -44
  35. package/openspec/schemas/playwright-e2e/schema.yaml +0 -56
  36. package/openspec/schemas/playwright-e2e/templates/e2e-test.ts +0 -55
  37. package/openspec/schemas/playwright-e2e/templates/playwright.config.ts +0 -52
  38. package/openspec/schemas/playwright-e2e/templates/report.md +0 -27
  39. package/openspec/schemas/playwright-e2e/templates/test-plan.md +0 -24
  40. package/openspec-playwright-0.1.62.tgz +0 -0
  41. package/release-notes.md +0 -5
  42. package/src/commands/doctor.ts +0 -115
  43. package/src/commands/editors.ts +0 -606
  44. package/src/commands/init.ts +0 -252
  45. package/src/commands/mcpSync.ts +0 -160
  46. package/src/commands/run.ts +0 -172
  47. package/src/commands/update.ts +0 -192
  48. package/src/index.ts +0 -47
  49. package/tests/editors.test.ts +0 -180
  50. package/tsconfig.json +0 -18
  51. package/vitest.config.ts +0 -9
@@ -1,180 +0,0 @@
1
- # OpenSpec + Playwright E2E Integration Design
2
-
3
- **Date:** 2026-03-26
4
- **Updated:** 2026-03-27
5
- **Status:** Implemented (MVP)
6
-
7
- ## Overview
8
-
9
- Integrate OpenSpec's spec-driven development workflow with Playwright Test Agents' three-agent harness (Planner / Generator / Healer) for automated E2E verification.
10
-
11
- **Design decision:** Add a new independent command `/openspec-e2e` rather than hooking into `/opsx:verify`. This keeps concerns separated and allows each verification to be run independently.
12
-
13
- ## Architecture
14
-
15
- ```
16
- openspec-pw (CLI - setup only)
17
- openspec-pw init → installs Playwright + configures MCP + installs skill
18
- openspec-pw doctor → checks prerequisites
19
-
20
- /openspec-e2e (Claude Code skill - runs in Claude)
21
-
22
- ├── 1. Read OpenSpec specs from openspec/changes/<name>/specs/
23
- ├── 2. Planner Agent → specs/playwright/test-plan.md
24
- ├── 3. Generator Agent → tests/playwright/<name>.spec.ts
25
- └── 4. Healer Agent → run tests + auto-heal
26
-
27
- └── Report: openspec/reports/playwright-e2e-<name>-<ts>.md
28
- ```
29
-
30
- ### Two Verification Layers
31
-
32
- | Layer | Command | Runs in | What it checks |
33
- |-------|---------|---------|----------------|
34
- | Static | `/opsx:verify` | Claude Code (OpenSpec skill) | Implementation matches artifacts |
35
- | E2E | `/openspec-e2e` | Claude Code (this skill) | App works when running |
36
-
37
- ## Key Design Decisions
38
-
39
- - **Separate command, not hook**: `/openspec-e2e` is independent from `/opsx:verify`. Users run them separately or together.
40
- - **CLI as setup only**: The CLI does not run agents. It only installs/configures. Agents run in Claude Code.
41
- - **Playwright MCP**: Playwright agents use the MCP protocol, configured in `.claude/settings.local.json`.
42
- - **Seed test**: A `tests/playwright/seed.spec.ts` template guides the Generator agent.
43
- - **No re-exploration**: Planner uses OpenSpec specs directly as the source of truth, no app exploration needed.
44
-
45
- ## CLI Commands
46
-
47
- ```bash
48
- npm install -g wxhou/openspec-playwright
49
-
50
- openspec-pw init # Setup: Playwright + MCP + skill + seed
51
- openspec-pw doctor # Check prerequisites
52
- ```
53
-
54
- ## What `openspec-pw init` Does
55
-
56
- 1. `npx playwright init-agents --loop=claude` — installs Playwright agents
57
- 2. Configure Playwright MCP in `.claude/settings.local.json`
58
- 3. Install skill: `.claude/skills/openspec-e2e/SKILL.md`
59
- 4. Install command: `.claude/commands/opsx-e2e.md`
60
- 5. Generate `tests/playwright/seed.spec.ts` template
61
-
62
- ## SKILL.md Format
63
-
64
- Follows the OpenSpec standard format:
65
- - YAML frontmatter: `name`, `description`, `license`, `compatibility`, `metadata`
66
- - Bold step names: `**Step 1: Name**`
67
- - Output fenced code blocks: `**Output During Implementation**`, `**Output On Completion**`
68
- - Guardrails section
69
- - Fluid Workflow Integration section
70
-
71
- ## Directory Structure
72
-
73
- ```
74
- project/
75
- ├── .claude/
76
- │ ├── skills/
77
- │ │ └── openspec-e2e/
78
- │ │ └── SKILL.md # The /openspec-e2e skill
79
- │ ├── commands/
80
- │ │ └── opsx-e2e.md # The /openspec-e2e command
81
- │ └── settings.local.json # Playwright MCP config
82
- ├── .github/ # Playwright agent definitions
83
- │ └── ...
84
- ├── openspec/
85
- │ ├── changes/<name>/
86
- │ │ ├── specs/
87
- │ │ │ ├── *.md # OpenSpec propose output
88
- │ │ │ └── playwright/
89
- │ │ │ └── test-plan.md # Planner output
90
- │ │ ├── design.md
91
- │ │ └── tasks.md
92
- │ └── reports/
93
- │ └── playwright-e2e-<name>-<ts>.md # Healer report
94
- └── tests/playwright/
95
- ├── seed.spec.ts # Seed test template
96
- └── <name>.spec.ts # Generated tests
97
- ```
98
-
99
- ## SKILL.md Sections (OpenSpec Standard)
100
-
101
- ```yaml
102
- ---
103
- name: openspec-e2e
104
- description: Run Playwright E2E verification for an OpenSpec change...
105
- license: MIT
106
- compatibility: Requires openspec CLI and Playwright Test Agents...
107
- metadata:
108
- author: openspec-playwright
109
- version: "0.1.0"
110
- generatedBy: "openspec-playwright"
111
- ---
112
-
113
- Run Playwright E2E verification for an OpenSpec change...
114
-
115
- ## Step 1: Identify the Change
116
- ...
117
-
118
- ## Step 2: Verify Prerequisites
119
- ...
120
-
121
- **Output During Implementation**
122
- ```markdown
123
- ## E2E Verification: <name>
124
- Status: 🔄 In Progress
125
- ```
126
- ```
127
-
128
- **Output On Completion**
129
- ```markdown
130
- ## E2E Verify Report: <name>
131
- | Check | Status |
132
- |-------|--------|
133
- ...
134
- ```
135
- ```
136
-
137
- **Guardrails**
138
- - Always read specs from `openspec/changes/<name>/specs/` as source of truth
139
- - Do not generate tests that contradict the specs
140
- - Cap auto-heal attempts at 3
141
- ...
142
-
143
- **Fluid Workflow Integration**
144
- - Before: /opsx:propose → /opsx:apply
145
- - This skill: /openspec-e2e
146
- - After: /opsx:archive
147
- ```
148
-
149
- ## Error Handling
150
-
151
- | Scenario | Action |
152
- |----------|--------|
153
- | No specs found | Prompt to run `/opsx:propose` first |
154
- | Prerequisites missing | Prompt to run `openspec-pw init` |
155
- | Dev server not running | Prompt to start before proceeding |
156
- | Planner fails | Log error, mark FAILED |
157
- | Generator fails | Log error, mark FAILED |
158
- | Healer guardrails trigger | Report failures, mark PARTIAL |
159
-
160
- ## Project Structure
161
-
162
- ```
163
- openspec-playwright/
164
- ├── src/
165
- │ ├── index.ts # CLI entry
166
- │ └── commands/
167
- │ ├── init.ts # openspec-pw init
168
- │ └── doctor.ts # openspec-pw doctor
169
- ├── .claude/
170
- │ ├── skills/
171
- │ │ └── openspec-e2e/
172
- │ │ └── SKILL.md # The Claude Code skill
173
- │ └── commands/
174
- │ └── opsx-e2e.md # The command file
175
- ├── templates/
176
- │ └── seed.spec.ts # Playwright seed test template
177
- ├── README.md
178
- ├── package.json
179
- └── tsconfig.json
180
- ```
@@ -1,44 +0,0 @@
1
- # Claude Code Employee-Grade Configuration
2
-
3
- > 员工级行为规范,适用于 OpenSpec 项目。
4
- > 遵循 OpenSpec 规范驱动开发流程(详见 /openspec/)。
5
-
6
- ---
7
-
8
- ## 一、代码质量
9
-
10
- **验证后才能报告成功**。运行项目的 linter 和 type checker:查看 `package.json`/`pyproject.toml`/`go.mod`/`Cargo.toml` 中的 scripts,使用对应的 `lint`/`typecheck` 命令。不存在时,明确告知用户,不得假装成功。
11
-
12
- **拒绝'够用就行'**。架构缺陷、状态重复、模式不一致——说出来并修复。高级工程师在 code review 中会拒绝什么?全部修掉。
13
-
14
- **安全防护**:防范 XSS、SQL 注入、命令注入(OWASP Top 10)。
15
-
16
- ---
17
-
18
- ## 二、上下文管理
19
-
20
- **文件读取完整**:超过 500 行的文件,不要假设单次读取覆盖了完整文件——根据需要分次读取相关段落,或编辑前重新读取完整文件。超过 10 条消息后,编辑任何文件前强制重新读取。
21
-
22
- **重构前清死代码**:未使用的 import/export/prop/console.log 先删掉,单独提交,再做重构。
23
-
24
- ---
25
-
26
- ## 三,大规模任务
27
-
28
- **子 Agent 并行化**:任务涉及超过 5 个独立文件时,启动并行子 agent(每个 5-8 个文件),每个拥有独立 token budget。
29
-
30
- **分阶段执行**:每个阶段不超过 5 个文件,完成后验证,等待用户批准再继续。
31
-
32
- ---
33
-
34
- ## 四、工具限制
35
-
36
- **搜索维度完整**:重命名函数/类型/变量时,必须覆盖:直接调用、类型级引用、字符串字面量、`require()`/`import`、barrel file、测试 mock。不得假设一次 grep 覆盖所有情况。
37
-
38
- ---
39
-
40
- ## 五、编辑安全
41
-
42
- **验证后才算完成**:编辑后再次读取确认变更正确应用。同一文件连续编辑不超过 3 次,中间必须验证。变更完成后,明确告知用户可能遗漏的区域(动态引用、测试 mock 等),提示人工复查。
43
-
44
- **不主动推送**:除非用户明确要求,否则不推送代码。
@@ -1,56 +0,0 @@
1
- name: playwright-e2e
2
- version: 1
3
- description: Playwright E2E verification for an OpenSpec change
4
-
5
- artifacts:
6
- - id: test-plan
7
- generates: specs/playwright/test-plan.md
8
- description: Test plan derived from change specs
9
- template: test-plan.md
10
- instruction: |
11
- Generate a test plan from the change specs. Each functional requirement becomes
12
- one or more test cases.
13
-
14
- For each test case, specify:
15
- - **Test name** (kebab-case): what it verifies
16
- - **Route/Page**: which URL or UI component it targets
17
- - **Prerequisites**: auth role needed (user/admin/guest/none)
18
- - **Happy path**: main user flow to verify
19
- - **Error paths**: key error conditions to verify
20
-
21
- Mark tests with role tags: `@role(user)`, `@role(admin)`, `@role(guest)`, `@role(none)`.
22
- Mark auth requirement: `@auth(required)` or `@auth(none)`.
23
-
24
- - id: e2e-test
25
- generates: tests/playwright/<change>.spec.ts
26
- description: Playwright E2E test suite
27
- template: e2e-test.ts
28
- instruction: |
29
- Generate Playwright tests from the test-plan.
30
-
31
- Rules:
32
- - Follow the page object pattern from seed.spec.ts
33
- - Prefer `data-testid` selectors, fall back to semantic selectors
34
- - Each test maps to one test case from the test-plan
35
- - Use `@project(user)` / `@project(admin)` for role-specific tests
36
- - Cover happy path AND key error paths
37
- - Name tests descriptively: `test('shows error on invalid input')`
38
-
39
- - id: playwright-config
40
- generates: playwright.config.ts
41
- description: Playwright config with webServer and auth projects
42
- template: playwright.config.ts
43
- instruction: |
44
- Configure Playwright for E2E testing.
45
-
46
- - Set webServer command and url from BASE_URL
47
- - Set baseURL for all tests
48
- - Add auth setup project if credentials are configured
49
- - Preserve any existing config fields (browsers, retries, etc.)
50
- - Do NOT overwrite existing projects unless they conflict
51
-
52
- apply:
53
- requires: [test-plan, e2e-test]
54
- instruction: |
55
- Run tests via: openspec-pw run <change-name>
56
- Analyze results and generate report at openspec/reports/playwright-e2e-<change>-<timestamp>.md
@@ -1,55 +0,0 @@
1
- import { test, expect, Page } from '@playwright/test';
2
-
3
- // ──────────────────────────────────────────────
4
- // Test plan: <change-name>
5
- // Generated from: openspec/changes/<change-name>/specs/playwright/test-plan.md
6
- // ──────────────────────────────────────────────
7
-
8
- const BASE_URL = process.env.BASE_URL || 'http://localhost:3000';
9
-
10
- /**
11
- * Page Object Pattern - add selectors for your app's pages
12
- */
13
- class AppPage {
14
- constructor(private page: Page) {}
15
-
16
- async goto(path: string = '/') {
17
- await this.page.goto(`${BASE_URL}${path}`);
18
- }
19
-
20
- async getByTestId(id: string) {
21
- return this.page.locator(`[data-testid="${id}"]`);
22
- }
23
-
24
- async waitForToast(message?: string) {
25
- if (message) {
26
- await this.page.getByText(message, { state: 'visible' }).waitFor();
27
- }
28
- }
29
- }
30
-
31
- function createPage(page: Page): AppPage {
32
- return new AppPage(page);
33
- }
34
-
35
- // ──────────────────────────────────────────────
36
- // Tests - generated from test-plan.md
37
- // Customize selectors and assertions to match your app
38
- // ──────────────────────────────────────────────
39
-
40
- test.describe('<change-name>: E2E verification', () => {
41
-
42
- test.beforeEach(async ({ page }) => {
43
- const app = createPage(page);
44
- await app.goto('/');
45
- });
46
-
47
- // TODO: Add test cases from specs/playwright/test-plan.md
48
- // Example:
49
- // test('shows expected content on page load', async ({ page }) => {
50
- // const app = createPage(page);
51
- // await app.goto('/');
52
- // await expect(app.getByTestId('main-heading')).toBeVisible();
53
- // });
54
-
55
- });
@@ -1,52 +0,0 @@
1
- import { defineConfig, devices } from '@playwright/test';
2
- import { readFileSync, existsSync } from 'fs';
3
- import { join } from 'path';
4
-
5
- // ─── BASE_URL: prefer env, then seed.spec.ts, then default ───
6
- const seedSpec = join(__dirname, '../tests/playwright/seed.spec.ts');
7
- let baseUrl = process.env.BASE_URL || 'http://localhost:3000';
8
- if (existsSync(seedSpec)) {
9
- const content = readFileSync(seedSpec, 'utf-8');
10
- const m = content.match(/BASE_URL\s*=\s*process\.env\.BASE_URL\s*\|\|\s*['"]([^'"]+)['"]/);
11
- if (m) baseUrl = m[1];
12
- }
13
-
14
- // ─── Dev command: detect from package.json scripts ───
15
- const pkgPath = join(__dirname, '../package.json');
16
- let devCmd = 'npm run dev';
17
- if (existsSync(pkgPath)) {
18
- const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
19
- const scripts = pkg.scripts ?? {};
20
- // Prefer in order: dev, start, serve, preview
21
- devCmd = scripts.dev ?? scripts.start ?? scripts.serve ?? scripts.preview ?? devCmd;
22
- }
23
-
24
- export default defineConfig({
25
- testDir: '../tests/playwright',
26
- // Keep test artifacts inside tests/playwright/ instead of project root
27
- outputDir: '../tests/playwright/test-results',
28
- fullyParallel: true,
29
- forbidOnly: !!process.env.CI,
30
- retries: process.env.CI ? 2 : 0,
31
- workers: process.env.CI ? 1 : undefined,
32
- reporter: 'list',
33
-
34
- use: {
35
- baseURL: baseUrl,
36
- trace: 'on-first-retry',
37
- },
38
-
39
- // Dev server lifecycle - Playwright starts/stops automatically
40
- webServer: {
41
- command: devCmd,
42
- url: baseUrl,
43
- timeout: 120000,
44
- reuseExistingServer: true,
45
- },
46
-
47
- // Setup project for authentication (configured by openspec-pw run)
48
- projects: [
49
- { name: 'setup', testMatch: /.*\.setup\.ts/ },
50
- { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
51
- ],
52
- });
@@ -1,27 +0,0 @@
1
- # E2E Verify Report: <change-name>
2
-
3
- **Change**: `<change-name>`
4
- **Generated**: `<timestamp>`
5
- **Auth**: `<required|none>`
6
-
7
- ## Summary
8
-
9
- | Check | Status |
10
- |-------|--------|
11
- | Tests Run | <N> |
12
- | Passed | <X> |
13
- | Failed | <Y> |
14
- | Auto-heals | <Z> |
15
- | Final Status | <PASS|FAIL> |
16
-
17
- ## Test Results
18
-
19
- <!-- List each test with pass/fail status -->
20
-
21
- ## Auto-Heal Log
22
-
23
- <!-- If heals were performed, document each attempt -->
24
-
25
- ## Recommendations
26
-
27
- <!-- For failed tests, specific file:line references and fixes -->
@@ -1,24 +0,0 @@
1
- # Test Plan: <change-name>
2
-
3
- Generated from: `openspec/changes/<change-name>/specs/`
4
-
5
- ## Auth Requirements
6
-
7
- <!-- Mark auth requirements based on specs analysis: -->
8
- - Auth required: **yes / no**
9
- - Roles needed: none / user / admin / user+admin
10
-
11
- ## Test Cases
12
-
13
- ### <test-name>
14
-
15
- - **Route**: `/<page>`
16
- - **Role**: `@role(<role>)`
17
- - **Auth**: `@auth(required|none)`
18
-
19
- **Happy path:**
20
- - Step 1: ...
21
- - Step 2: ...
22
-
23
- **Error paths:**
24
- - ...
Binary file
package/release-notes.md DELETED
@@ -1,5 +0,0 @@
1
- ## What's Changed
2
-
3
- - chore: bump version to 0.1.62
4
-
5
- **Full Changelog**: https://github.com/wxhou/openspec-playwright/releases/tag/v0.1.62
@@ -1,115 +0,0 @@
1
- import { existsSync, readFileSync } from 'fs';
2
- import { join } from 'path';
3
- import { homedir } from 'os';
4
- import { execSync } from 'child_process';
5
- import chalk from 'chalk';
6
-
7
- export async function doctor() {
8
- console.log(chalk.blue('\n🔍 OpenSpec + Playwright E2E Prerequisites Check\n'));
9
-
10
- const projectRoot = process.cwd();
11
- let allOk = true;
12
-
13
- // Node.js
14
- console.log(chalk.blue('─── Node.js ───'));
15
- try {
16
- const node = execSync('node --version', { encoding: 'utf-8' }).trim();
17
- console.log(chalk.green(` ✓ Node.js ${node}`));
18
- } catch {
19
- console.log(chalk.red(' ✗ Node.js not found'));
20
- allOk = false;
21
- }
22
-
23
- // npm
24
- console.log(chalk.blue('\n─── npm ───'));
25
- try {
26
- const npm = execSync('npm --version', { encoding: 'utf-8' }).trim();
27
- console.log(chalk.green(` ✓ npm ${npm}`));
28
- } catch {
29
- console.log(chalk.red(' ✗ npm not found'));
30
- allOk = false;
31
- }
32
-
33
- // OpenSpec
34
- console.log(chalk.blue('\n─── OpenSpec ───'));
35
- const hasOpenSpec = existsSync(join(projectRoot, 'openspec'));
36
- if (hasOpenSpec) {
37
- console.log(chalk.green(' ✓ OpenSpec initialized'));
38
- } else {
39
- console.log(chalk.red(' ✗ OpenSpec not initialized'));
40
- console.log(chalk.gray(' Run: openspec init'));
41
- allOk = false;
42
- }
43
-
44
- // Playwright browsers
45
- console.log(chalk.blue('\n─── Playwright Browsers ───'));
46
- try {
47
- const pw = execSync('npx playwright --version', { encoding: 'utf-8' }).trim();
48
- console.log(chalk.green(` ✓ Playwright ${pw}`));
49
- } catch {
50
- console.log(chalk.red(' ✗ Playwright browsers not installed'));
51
- console.log(chalk.gray(' Run: npx playwright install --with-deps'));
52
- allOk = false;
53
- }
54
-
55
- // Playwright MCP (global)
56
- console.log(chalk.blue('\n─── Playwright MCP ───'));
57
- const homeDir = homedir();
58
- const claudeJsonPath = join(homeDir, '.claude.json');
59
- let mcpInstalled = false;
60
- if (existsSync(claudeJsonPath)) {
61
- try {
62
- const claudeJson = JSON.parse(readFileSync(claudeJsonPath, 'utf-8'));
63
- const globalMcp = claudeJson?.mcpServers ?? {};
64
- const localMcp = claudeJson?.projects?.[projectRoot]?.mcpServers ?? {};
65
- if (globalMcp['playwright'] || localMcp['playwright']) {
66
- mcpInstalled = true;
67
- }
68
- } catch {
69
- // ignore
70
- }
71
- }
72
- if (mcpInstalled) {
73
- console.log(chalk.green(' ✓ Playwright MCP installed globally'));
74
- } else {
75
- console.log(chalk.red(' ✗ Playwright MCP not configured'));
76
- console.log(chalk.gray(' Run: openspec-pw init'));
77
- allOk = false;
78
- }
79
-
80
- // Skill
81
- console.log(chalk.blue('\n─── Claude Code Skill ───'));
82
- const hasSkill = existsSync(
83
- join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md')
84
- );
85
- if (hasSkill) {
86
- console.log(chalk.green(' ✓ /openspec-e2e skill installed'));
87
- } else {
88
- console.log(chalk.red(' ✗ Skill not installed'));
89
- console.log(chalk.gray(' Run: openspec-pw init'));
90
- allOk = false;
91
- }
92
-
93
- // Seed test
94
- console.log(chalk.blue('\n─── Seed Test ───'));
95
- const hasSeed = existsSync(
96
- join(projectRoot, 'tests', 'playwright', 'seed.spec.ts')
97
- );
98
- if (hasSeed) {
99
- console.log(chalk.green(' ✓ seed.spec.ts found'));
100
- } else {
101
- console.log(chalk.yellow(' ⚠ seed.spec.ts not found (optional)'));
102
- console.log(chalk.gray(' Run: openspec-pw init'));
103
- }
104
-
105
- // Summary
106
- console.log(chalk.blue('\n─── Summary ───'));
107
- if (allOk) {
108
- console.log(chalk.green(' ✅ All prerequisites met!\n'));
109
- console.log(chalk.gray(' Run: /opsx:e2e <change-name> in Claude Code\n'));
110
- } else {
111
- console.log(chalk.red(' ❌ Some prerequisites are missing\n'));
112
- console.log(chalk.gray(' Run: openspec-pw init to fix\n'));
113
- process.exit(1);
114
- }
115
- }