openspec-playwright 0.1.38 → 0.1.39

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.
@@ -0,0 +1,39 @@
1
+ Run Playwright E2E verification for an OpenSpec change.
2
+
3
+ ## Workflow
4
+
5
+ 1. **Validate environment**: Run the seed test to confirm your app is reachable.
6
+ ```bash
7
+ npx playwright test tests/playwright/seed.spec.ts --project=chromium
8
+ ```
9
+ If it fails, fix your BASE_URL or start the dev server first.
10
+
11
+ 2. **Select the change**: If no change name is provided, run `openspec list --json` and pick one. Then announce: "Using change: `<name>`".
12
+
13
+ 3. **Read specs**: Read all files from `openspec/changes/<name>/specs/*.md`.
14
+
15
+ 4. **Detect auth**: Check if specs mention login, protected routes, or session handling. See `tests/playwright/auth.setup.ts` for auth setup.
16
+
17
+ 5. **Generate test plan**: Create `openspec/changes/<name>/specs/playwright/test-plan.md` listing each test case with `@auth(required|none)` and `@role(...)` tags. Skip if already exists.
18
+
19
+ 6. **Generate tests**: Write `tests/playwright/<name>.spec.ts` from the test plan. Follow the patterns in `seed.spec.ts`:
20
+ - Prefer `data-testid`, fallback to `getByRole`, `getByLabel`, `getByText`
21
+ - Include happy path AND error/edge cases
22
+ - Never use conditional `if (isVisible())` — always use `expect().toBeVisible()` (false-pass anti-pattern)
23
+ - Use `browser.newContext()` for auth guard tests (fresh session, no cookies)
24
+
25
+ 7. **Run tests**:
26
+ ```bash
27
+ openspec-pw run <change-name>
28
+ ```
29
+ Or with role filtering:
30
+ ```bash
31
+ npx playwright test tests/playwright/<name>.spec.ts --grep "@<role>"
32
+ ```
33
+
34
+ 8. **Fix failures**: If tests fail, analyze the error:
35
+ - Network/backend error → `test.skip()` + report
36
+ - Selector changed → use Playwright MCP tools to find equivalent selectors, fix, re-run
37
+ - Auto-heal up to 3 attempts
38
+
39
+ 9. **Report**: Results are saved to `openspec/reports/playwright-e2e-<name>-<timestamp>.md`. Present the summary table to the user.
@@ -0,0 +1,35 @@
1
+ /** Shared YAML escape — matches OpenSpec's escape logic */
2
+ export declare function escapeYamlValue(value: string): string;
3
+ /** Format tags as YAML inline array */
4
+ export declare function formatTagsArray(tags: string[]): string;
5
+ /** Command metadata shared across editors */
6
+ export interface CommandMeta {
7
+ id: string;
8
+ name: string;
9
+ description: string;
10
+ category: string;
11
+ tags: string[];
12
+ body: string;
13
+ }
14
+ /** Editor adapter — Strategy Pattern */
15
+ export interface EditorAdapter {
16
+ /** Tool identifier */
17
+ toolId: string;
18
+ /** Whether this editor supports SKILL.md */
19
+ hasSkill: boolean;
20
+ /** Get the command file path relative to project root */
21
+ getCommandPath(commandId: string): string;
22
+ /** Format the complete file content */
23
+ formatCommand(meta: CommandMeta): string;
24
+ }
25
+ /** Claude Code: .claude/commands/opsx/<id>.md + SKILL.md */
26
+ declare const claudeAdapter: EditorAdapter;
27
+ /** Detect which editors are installed by checking their config directories */
28
+ export declare function detectEditors(projectRoot: string): EditorAdapter[];
29
+ /** Build the shared command metadata */
30
+ export declare function buildCommandMeta(body: string): CommandMeta;
31
+ /** Install command files for all detected editors */
32
+ export declare function installForAllEditors(body: string, adapters: EditorAdapter[], projectRoot: string): void;
33
+ /** Install SKILL.md only for Claude Code */
34
+ export declare function installSkill(projectRoot: string, skillContent: string): void;
35
+ export { claudeAdapter };
@@ -0,0 +1,159 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import chalk from 'chalk';
4
+ /** Shared YAML escape — matches OpenSpec's escape logic */
5
+ export function escapeYamlValue(value) {
6
+ const needsQuoting = /[:\n\r#{}[\],&*!|>'"%@`]|^\s|\s$/.test(value);
7
+ if (needsQuoting) {
8
+ const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n');
9
+ return `"${escaped}"`;
10
+ }
11
+ return value;
12
+ }
13
+ /** Format tags as YAML inline array */
14
+ export function formatTagsArray(tags) {
15
+ return `[${tags.map(t => escapeYamlValue(t)).join(', ')}]`;
16
+ }
17
+ /** Claude Code: .claude/commands/opsx/<id>.md + SKILL.md */
18
+ const claudeAdapter = {
19
+ toolId: 'claude',
20
+ hasSkill: true,
21
+ getCommandPath(id) {
22
+ return join('.claude', 'commands', 'opsx', `${id}.md`);
23
+ },
24
+ formatCommand(meta) {
25
+ return `---
26
+ name: ${escapeYamlValue(meta.name)}
27
+ description: ${escapeYamlValue(meta.description)}
28
+ category: ${escapeYamlValue(meta.category)}
29
+ tags: ${formatTagsArray(meta.tags)}
30
+ ---
31
+
32
+ ${meta.body}
33
+ `;
34
+ },
35
+ };
36
+ /** Cursor: .cursor/commands/opsx-<id>.md */
37
+ const cursorAdapter = {
38
+ toolId: 'cursor',
39
+ hasSkill: false,
40
+ getCommandPath(id) {
41
+ return join('.cursor', 'commands', `opsx-${id}.md`);
42
+ },
43
+ formatCommand(meta) {
44
+ return `---
45
+ name: /opsx-${meta.id}
46
+ id: opsx-${meta.id}
47
+ category: ${escapeYamlValue(meta.category)}
48
+ description: ${escapeYamlValue(meta.description)}
49
+ ---
50
+
51
+ ${meta.body}
52
+ `;
53
+ },
54
+ };
55
+ /** Windsurf: .windsurf/workflows/opsx-<id>.md */
56
+ const windsurfAdapter = {
57
+ toolId: 'windsurf',
58
+ hasSkill: false,
59
+ getCommandPath(id) {
60
+ return join('.windsurf', 'workflows', `opsx-${id}.md`);
61
+ },
62
+ formatCommand(meta) {
63
+ return `---
64
+ name: ${escapeYamlValue(meta.name)}
65
+ description: ${escapeYamlValue(meta.description)}
66
+ category: ${escapeYamlValue(meta.category)}
67
+ tags: ${formatTagsArray(meta.tags)}
68
+ ---
69
+
70
+ ${meta.body}
71
+ `;
72
+ },
73
+ };
74
+ /** Cline: .clinerules/workflows/opsx-<id>.md — markdown header only */
75
+ const clineAdapter = {
76
+ toolId: 'cline',
77
+ hasSkill: false,
78
+ getCommandPath(id) {
79
+ return join('.clinerules', 'workflows', `opsx-${id}.md`);
80
+ },
81
+ formatCommand(meta) {
82
+ return `# ${meta.name}
83
+
84
+ ${meta.description}
85
+
86
+ ${meta.body}
87
+ `;
88
+ },
89
+ };
90
+ /** Continue: .continue/prompts/opsx-<id>.prompt */
91
+ const continueAdapter = {
92
+ toolId: 'continue',
93
+ hasSkill: false,
94
+ getCommandPath(id) {
95
+ return join('.continue', 'prompts', `opsx-${id}.prompt`);
96
+ },
97
+ formatCommand(meta) {
98
+ return `---
99
+ name: opsx-${meta.id}
100
+ description: ${meta.description}
101
+ invokable: true
102
+ ---
103
+
104
+ ${meta.body}
105
+ `;
106
+ },
107
+ };
108
+ /** All supported adapters */
109
+ const ALL_ADAPTERS = [
110
+ claudeAdapter,
111
+ cursorAdapter,
112
+ windsurfAdapter,
113
+ clineAdapter,
114
+ continueAdapter,
115
+ ];
116
+ /** Detect which editors are installed by checking their config directories */
117
+ export function detectEditors(projectRoot) {
118
+ const checks = [
119
+ ['.claude', claudeAdapter],
120
+ ['.cursor', cursorAdapter],
121
+ ['.windsurf', windsurfAdapter],
122
+ ['.clinerules', clineAdapter],
123
+ ['.continue', continueAdapter],
124
+ ];
125
+ return checks
126
+ .filter(([dir]) => existsSync(join(projectRoot, dir)))
127
+ .map(([, adapter]) => adapter);
128
+ }
129
+ /** Build the shared command metadata */
130
+ export function buildCommandMeta(body) {
131
+ return {
132
+ id: 'e2e',
133
+ name: 'OPSX: E2E',
134
+ description: 'Run Playwright E2E verification for an OpenSpec change',
135
+ category: 'OpenSpec',
136
+ tags: ['openspec', 'playwright', 'e2e', 'testing'],
137
+ body,
138
+ };
139
+ }
140
+ /** Install command files for all detected editors */
141
+ export function installForAllEditors(body, adapters, projectRoot) {
142
+ const meta = buildCommandMeta(body);
143
+ for (const adapter of adapters) {
144
+ const relPath = adapter.getCommandPath(meta.id);
145
+ const absPath = join(projectRoot, relPath);
146
+ mkdirSync(dirname(absPath), { recursive: true });
147
+ writeFileSync(absPath, adapter.formatCommand(meta));
148
+ console.log(chalk.green(` ✓ ${adapter.toolId}: ${relPath}`));
149
+ }
150
+ }
151
+ /** Install SKILL.md only for Claude Code */
152
+ export function installSkill(projectRoot, skillContent) {
153
+ const skillDir = join(projectRoot, '.claude', 'skills', 'openspec-e2e');
154
+ mkdirSync(skillDir, { recursive: true });
155
+ writeFileSync(join(skillDir, 'SKILL.md'), skillContent);
156
+ console.log(chalk.green(` ✓ claude: .claude/skills/openspec-e2e/SKILL.md`));
157
+ }
158
+ export { claudeAdapter };
159
+ //# sourceMappingURL=editors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editors.js","sourceRoot":"","sources":["../../src/commands/editors.ts"],"names":[],"mappings":"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"}
@@ -6,10 +6,11 @@ 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, installForAllEditors, installSkill, claudeAdapter } from './editors.js';
9
10
  const TEMPLATE_DIR = fileURLToPath(new URL('../../templates', import.meta.url));
10
11
  const SCHEMA_DIR = fileURLToPath(new URL('../../schemas', import.meta.url));
11
- const SKILL_SRC = fileURLToPath(new URL('../../.claude/skills/openspec-e2e', import.meta.url));
12
- const CMD_SRC = fileURLToPath(new URL('../../.claude/commands/opsx/e2e.md', import.meta.url));
12
+ const SKILL_SRC = fileURLToPath(new URL('../../.claude/skills/openspec-e2e/SKILL.md', import.meta.url));
13
+ const CMD_BODY_SRC = fileURLToPath(new URL('../../.claude/commands/opsx/e2e-body.md', import.meta.url));
13
14
  export async function init(options) {
14
15
  console.log(chalk.blue('\n🔧 OpenSpec + Playwright E2E Setup\n'));
15
16
  const projectRoot = process.cwd();
@@ -61,13 +62,32 @@ export async function init(options) {
61
62
  }
62
63
  }
63
64
  }
64
- // 4. Copy skill files
65
- console.log(chalk.blue('\n─── Installing Claude Code Skill ───'));
66
- await installSkill(projectRoot);
67
- // 5. Sync Healer tools with latest @playwright/mcp
68
- console.log(chalk.blue('\n─── Syncing Healer Tools ───'));
69
- const skillDest = join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
70
- await syncMcpTools(skillDest, true);
65
+ // 4. Install E2E commands for detected editors
66
+ console.log(chalk.blue('\n─── Installing E2E Commands ───'));
67
+ const detected = detectEditors(projectRoot);
68
+ if (detected.length > 0) {
69
+ const body = await readFile(CMD_BODY_SRC, 'utf-8');
70
+ installForAllEditors(body, detected, projectRoot);
71
+ }
72
+ else {
73
+ const body = await readFile(CMD_BODY_SRC, 'utf-8');
74
+ installForAllEditors(body, [claudeAdapter], projectRoot);
75
+ }
76
+ // Claude Code also gets the SKILL.md
77
+ if (existsSync(join(projectRoot, '.claude'))) {
78
+ const skillContent = await readFile(SKILL_SRC, 'utf-8');
79
+ installSkill(projectRoot, skillContent);
80
+ }
81
+ // 5. Sync Healer tools with latest @playwright/mcp (Claude Code only)
82
+ if (existsSync(join(projectRoot, '.claude'))) {
83
+ console.log(chalk.blue('\n─── Syncing Healer Tools ───'));
84
+ const skillDest = join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
85
+ await syncMcpTools(skillDest, true);
86
+ }
87
+ else {
88
+ console.log(chalk.blue('\n─── Syncing Healer Tools ───'));
89
+ console.log(chalk.gray(' - Claude Code not detected, skipping MCP sync'));
90
+ }
71
91
  // 6. Install OpenSpec schema
72
92
  console.log(chalk.blue('\n─── Installing OpenSpec Schema ───'));
73
93
  await installSchema(projectRoot);
@@ -84,28 +104,17 @@ export async function init(options) {
84
104
  console.log(chalk.gray(' 2. Customize tests/playwright/credentials.yaml with your test user'));
85
105
  console.log(chalk.gray(' 3. Set credentials: export E2E_USERNAME=xxx E2E_PASSWORD=yyy'));
86
106
  console.log(chalk.gray(' 4. Run auth setup: npx playwright test --project=setup'));
87
- console.log(chalk.gray(' 5. In Claude Code, run: /opsx:e2e <change-name>'));
88
- console.log(chalk.gray(' 6. Or: openspec-pw doctor to verify setup\n'));
107
+ const hasClaude = existsSync(join(projectRoot, '.claude'));
108
+ if (hasClaude) {
109
+ console.log(chalk.gray(' 5. In Claude Code, run: /opsx:e2e <change-name>'));
110
+ }
111
+ console.log(chalk.gray(` ${hasClaude ? '6.' : '5.'} Or: openspec-pw run <change-name>`));
112
+ console.log(chalk.gray(` ${hasClaude ? '7.' : '6.'} Or: openspec-pw doctor to verify setup\n`));
89
113
  console.log(chalk.bold('How it works:'));
90
114
  console.log(chalk.gray(' /opsx:e2e reads your OpenSpec specs and runs Playwright'));
91
115
  console.log(chalk.gray(' E2E tests through a three-agent pipeline:'));
92
116
  console.log(chalk.gray(' Planner → Generator → Healer\n'));
93
117
  }
94
- async function installSkill(projectRoot) {
95
- const skillsDir = join(projectRoot, '.claude', 'skills');
96
- const skillDir = join(skillsDir, 'openspec-e2e');
97
- const cmdDir = join(projectRoot, '.claude', 'commands');
98
- // Copy skill
99
- mkdirSync(skillDir, { recursive: true });
100
- const skillContent = await readFile(SKILL_SRC + '/SKILL.md', 'utf-8');
101
- writeFileSync(join(skillDir, 'SKILL.md'), skillContent);
102
- console.log(chalk.green(` ✓ Skill installed: /openspec-e2e`));
103
- // Copy command
104
- mkdirSync(join(cmdDir, 'opsx'), { recursive: true });
105
- const cmdContent = await readFile(CMD_SRC, 'utf-8');
106
- writeFileSync(join(cmdDir, 'opsx', 'e2e.md'), cmdContent);
107
- console.log(chalk.green(` ✓ Command installed: /opsx:e2e`));
108
- }
109
118
  async function generateSeedTest(projectRoot) {
110
119
  const testsDir = join(projectRoot, 'tests', 'playwright');
111
120
  mkdirSync(testsDir, { recursive: true });
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -7,8 +7,8 @@ import { fileURLToPath } from 'url';
7
7
  import chalk from 'chalk';
8
8
  import * as tar from 'tar';
9
9
  import { syncMcpTools } from './mcpSync.js';
10
- const SKILL_SRC = fileURLToPath(new URL('../../.claude/skills/openspec-e2e', import.meta.url));
11
- const CMD_SRC = fileURLToPath(new URL('../../.claude/commands/opsx', import.meta.url));
10
+ import { detectEditors, installForAllEditors, installSkill } from './editors.js';
11
+ const CMD_BODY_SRC = fileURLToPath(new URL('../../.claude/commands/opsx/e2e-body.md', import.meta.url));
12
12
  const SCHEMA_DIR = fileURLToPath(new URL('../../schemas', import.meta.url));
13
13
  export async function update(options) {
14
14
  console.log(chalk.blue('\n🔄 Updating OpenSpec + Playwright E2E\n'));
@@ -33,9 +33,9 @@ export async function update(options) {
33
33
  console.log(chalk.gray(' Run manually: npm install -g openspec-playwright'));
34
34
  }
35
35
  }
36
- // 2. Update skill and command from npm tarball
36
+ // 2. Update commands for all detected editors + schema
37
37
  if (options.skill !== false) {
38
- console.log(chalk.blue('\n─── Updating Skill & Command ───'));
38
+ console.log(chalk.blue('\n─── Updating Commands & Schema ───'));
39
39
  try {
40
40
  const tmpDir = join(tmpdir(), 'openspec-e2e-update');
41
41
  rmSync(tmpDir, { recursive: true, force: true });
@@ -52,15 +52,27 @@ export async function update(options) {
52
52
  const tarballPath = join(tmpDir, tgzFiles[0].name);
53
53
  // Extract tarball
54
54
  await tar.extract({ file: tarballPath, cwd: tmpDir, strip: 1 });
55
- const skillSrc = join(tmpDir, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
56
- const cmdSrc = join(tmpDir, '.claude', 'commands', 'opsx', 'e2e.md');
55
+ const bodySrc = join(tmpDir, '.claude', 'commands', 'opsx', 'e2e-body.md');
57
56
  const schemaSrc = join(tmpDir, 'schemas', 'playwright-e2e');
58
- installSkillFrom(skillSrc, cmdSrc, schemaSrc, projectRoot);
57
+ // Install commands for all detected editors
58
+ const adapters = detectEditors(projectRoot);
59
+ if (adapters.length > 0 && existsSync(bodySrc)) {
60
+ const body = readFileSync(bodySrc, 'utf-8');
61
+ installForAllEditors(body, adapters, projectRoot);
62
+ }
63
+ // Install SKILL.md for Claude Code
64
+ const skillSrc = join(tmpDir, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
65
+ if (existsSync(join(projectRoot, '.claude')) && existsSync(skillSrc)) {
66
+ const skillContent = readFileSync(skillSrc, 'utf-8');
67
+ installSkill(projectRoot, skillContent);
68
+ }
69
+ // Install schema
70
+ installSchemaFrom(schemaSrc, projectRoot);
59
71
  rmSync(tmpDir, { recursive: true, force: true });
60
- console.log(chalk.green(' ✓ Skill & command updated to latest'));
72
+ console.log(chalk.green(' ✓ Commands & schema updated to latest'));
61
73
  }
62
74
  catch {
63
- console.log(chalk.yellow(' ⚠ Failed to update skill/command from npm'));
75
+ console.log(chalk.yellow(' ⚠ Failed to update from npm'));
64
76
  console.log(chalk.gray(' Trying npm install to pull latest version...'));
65
77
  try {
66
78
  execSync('npm install -g openspec-playwright', { stdio: 'inherit', cwd: projectRoot });
@@ -72,31 +84,23 @@ export async function update(options) {
72
84
  }
73
85
  }
74
86
  }
75
- // 3. Sync Healer tools with latest @playwright/mcp
76
- console.log(chalk.blue('\n─── Syncing Healer Tools ───'));
77
- const skillDest = join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
78
- await syncMcpTools(skillDest, true);
87
+ // 3. Sync Healer tools (Claude Code only)
88
+ if (existsSync(join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md'))) {
89
+ console.log(chalk.blue('\n─── Syncing Healer Tools ───'));
90
+ const skillDest = join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
91
+ await syncMcpTools(skillDest, true);
92
+ }
79
93
  // Summary
80
94
  console.log(chalk.blue('\n─── Summary ───'));
81
95
  console.log(chalk.green(' ✓ Update complete!\n'));
82
- console.log(chalk.bold('Restart Claude Code to use the updated skill.'));
83
- console.log(chalk.gray(' Then run /opsx:e2e <change-name> to verify.\n'));
84
- }
85
- function installSkill(projectRoot) {
86
- installSkillFrom(join(SKILL_SRC, 'SKILL.md'), join(CMD_SRC, 'e2e.md'), join(SCHEMA_DIR, 'playwright-e2e'), projectRoot);
87
- }
88
- function installSkillFrom(skillSrc, cmdSrc, schemaSrc, projectRoot) {
89
- const skillDir = join(projectRoot, '.claude', 'skills', 'openspec-e2e');
90
- const cmdDir = join(projectRoot, '.claude', 'commands');
91
- mkdirSync(skillDir, { recursive: true });
92
- const skillContent = readFileSync(skillSrc, 'utf-8');
93
- writeFileSync(join(skillDir, 'SKILL.md'), skillContent);
94
- console.log(chalk.green(` ✓ Skill updated: /openspec-e2e`));
95
- mkdirSync(join(cmdDir, 'opsx'), { recursive: true });
96
- const cmdContent = readFileSync(cmdSrc, 'utf-8');
97
- writeFileSync(join(cmdDir, 'opsx', 'e2e.md'), cmdContent);
98
- console.log(chalk.green(` ✓ Command updated: /opsx:e2e`));
99
- installSchemaFrom(schemaSrc, projectRoot);
96
+ if (existsSync(join(projectRoot, '.claude'))) {
97
+ console.log(chalk.bold('Restart Claude Code to use the updated skill.'));
98
+ console.log(chalk.gray(' Then run /opsx:e2e <change-name> to verify.\n'));
99
+ }
100
+ else {
101
+ console.log(chalk.bold('Restart your AI coding assistant to use the updated commands.'));
102
+ console.log(chalk.gray(' Then run openspec-pw run <change-name> to verify.\n'));
103
+ }
100
104
  }
101
105
  function installSchemaFrom(schemaSrc, projectRoot) {
102
106
  const schemaDest = join(projectRoot, 'openspec', 'schemas', 'playwright-e2e');
@@ -1 +1 @@
1
- {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openspec-playwright",
3
- "version": "0.1.38",
3
+ "version": "0.1.39",
4
4
  "description": "OpenSpec + Playwright E2E verification setup tool for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {
package/release-notes.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ## What's Changed
2
2
 
3
- - 0.1.38
3
+ - feat: support Top 5 editors via adapter pattern
4
4
 
5
- **Full Changelog**: https://github.com/wxhou/openspec-playwright/releases/tag/v0.1.38
5
+ **Full Changelog**: https://github.com/wxhou/openspec-playwright/releases/tag/v0.1.39
@@ -0,0 +1,199 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import chalk from 'chalk';
4
+
5
+ /** Shared YAML escape — matches OpenSpec's escape logic */
6
+ export function escapeYamlValue(value: string): string {
7
+ const needsQuoting = /[:\n\r#{}[\],&*!|>'"%@`]|^\s|\s$/.test(value);
8
+ if (needsQuoting) {
9
+ const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n');
10
+ return `"${escaped}"`;
11
+ }
12
+ return value;
13
+ }
14
+
15
+ /** Format tags as YAML inline array */
16
+ export function formatTagsArray(tags: string[]): string {
17
+ return `[${tags.map(t => escapeYamlValue(t)).join(', ')}]`;
18
+ }
19
+
20
+ /** Command metadata shared across editors */
21
+ export interface CommandMeta {
22
+ id: string;
23
+ name: string;
24
+ description: string;
25
+ category: string;
26
+ tags: string[];
27
+ body: string;
28
+ }
29
+
30
+ /** Editor adapter — Strategy Pattern */
31
+ export interface EditorAdapter {
32
+ /** Tool identifier */
33
+ toolId: string;
34
+ /** Whether this editor supports SKILL.md */
35
+ hasSkill: boolean;
36
+ /** Get the command file path relative to project root */
37
+ getCommandPath(commandId: string): string;
38
+ /** Format the complete file content */
39
+ formatCommand(meta: CommandMeta): string;
40
+ }
41
+
42
+ /** Claude Code: .claude/commands/opsx/<id>.md + SKILL.md */
43
+ const claudeAdapter: EditorAdapter = {
44
+ toolId: 'claude',
45
+ hasSkill: true,
46
+ getCommandPath(id: string) {
47
+ return join('.claude', 'commands', 'opsx', `${id}.md`);
48
+ },
49
+ formatCommand(meta) {
50
+ return `---
51
+ name: ${escapeYamlValue(meta.name)}
52
+ description: ${escapeYamlValue(meta.description)}
53
+ category: ${escapeYamlValue(meta.category)}
54
+ tags: ${formatTagsArray(meta.tags)}
55
+ ---
56
+
57
+ ${meta.body}
58
+ `;
59
+ },
60
+ };
61
+
62
+ /** Cursor: .cursor/commands/opsx-<id>.md */
63
+ const cursorAdapter: EditorAdapter = {
64
+ toolId: 'cursor',
65
+ hasSkill: false,
66
+ getCommandPath(id: string) {
67
+ return join('.cursor', 'commands', `opsx-${id}.md`);
68
+ },
69
+ formatCommand(meta) {
70
+ return `---
71
+ name: /opsx-${meta.id}
72
+ id: opsx-${meta.id}
73
+ category: ${escapeYamlValue(meta.category)}
74
+ description: ${escapeYamlValue(meta.description)}
75
+ ---
76
+
77
+ ${meta.body}
78
+ `;
79
+ },
80
+ };
81
+
82
+ /** Windsurf: .windsurf/workflows/opsx-<id>.md */
83
+ const windsurfAdapter: EditorAdapter = {
84
+ toolId: 'windsurf',
85
+ hasSkill: false,
86
+ getCommandPath(id: string) {
87
+ return join('.windsurf', 'workflows', `opsx-${id}.md`);
88
+ },
89
+ formatCommand(meta) {
90
+ return `---
91
+ name: ${escapeYamlValue(meta.name)}
92
+ description: ${escapeYamlValue(meta.description)}
93
+ category: ${escapeYamlValue(meta.category)}
94
+ tags: ${formatTagsArray(meta.tags)}
95
+ ---
96
+
97
+ ${meta.body}
98
+ `;
99
+ },
100
+ };
101
+
102
+ /** Cline: .clinerules/workflows/opsx-<id>.md — markdown header only */
103
+ const clineAdapter: EditorAdapter = {
104
+ toolId: 'cline',
105
+ hasSkill: false,
106
+ getCommandPath(id: string) {
107
+ return join('.clinerules', 'workflows', `opsx-${id}.md`);
108
+ },
109
+ formatCommand(meta) {
110
+ return `# ${meta.name}
111
+
112
+ ${meta.description}
113
+
114
+ ${meta.body}
115
+ `;
116
+ },
117
+ };
118
+
119
+ /** Continue: .continue/prompts/opsx-<id>.prompt */
120
+ const continueAdapter: EditorAdapter = {
121
+ toolId: 'continue',
122
+ hasSkill: false,
123
+ getCommandPath(id: string) {
124
+ return join('.continue', 'prompts', `opsx-${id}.prompt`);
125
+ },
126
+ formatCommand(meta) {
127
+ return `---
128
+ name: opsx-${meta.id}
129
+ description: ${meta.description}
130
+ invokable: true
131
+ ---
132
+
133
+ ${meta.body}
134
+ `;
135
+ },
136
+ };
137
+
138
+ /** All supported adapters */
139
+ const ALL_ADAPTERS: EditorAdapter[] = [
140
+ claudeAdapter,
141
+ cursorAdapter,
142
+ windsurfAdapter,
143
+ clineAdapter,
144
+ continueAdapter,
145
+ ];
146
+
147
+ /** Detect which editors are installed by checking their config directories */
148
+ export function detectEditors(projectRoot: string): EditorAdapter[] {
149
+ const checks: Array<[string, EditorAdapter]> = [
150
+ ['.claude', claudeAdapter],
151
+ ['.cursor', cursorAdapter],
152
+ ['.windsurf', windsurfAdapter],
153
+ ['.clinerules', clineAdapter],
154
+ ['.continue', continueAdapter],
155
+ ];
156
+
157
+ return checks
158
+ .filter(([dir]) => existsSync(join(projectRoot, dir)))
159
+ .map(([, adapter]) => adapter);
160
+ }
161
+
162
+ /** Build the shared command metadata */
163
+ export function buildCommandMeta(body: string): CommandMeta {
164
+ return {
165
+ id: 'e2e',
166
+ name: 'OPSX: E2E',
167
+ description: 'Run Playwright E2E verification for an OpenSpec change',
168
+ category: 'OpenSpec',
169
+ tags: ['openspec', 'playwright', 'e2e', 'testing'],
170
+ body,
171
+ };
172
+ }
173
+
174
+ /** Install command files for all detected editors */
175
+ export function installForAllEditors(
176
+ body: string,
177
+ adapters: EditorAdapter[],
178
+ projectRoot: string
179
+ ): void {
180
+ const meta = buildCommandMeta(body);
181
+
182
+ for (const adapter of adapters) {
183
+ const relPath = adapter.getCommandPath(meta.id);
184
+ const absPath = join(projectRoot, relPath);
185
+ mkdirSync(dirname(absPath), { recursive: true });
186
+ writeFileSync(absPath, adapter.formatCommand(meta));
187
+ console.log(chalk.green(` ✓ ${adapter.toolId}: ${relPath}`));
188
+ }
189
+ }
190
+
191
+ /** Install SKILL.md only for Claude Code */
192
+ export function installSkill(projectRoot: string, skillContent: string): void {
193
+ const skillDir = join(projectRoot, '.claude', 'skills', 'openspec-e2e');
194
+ mkdirSync(skillDir, { recursive: true });
195
+ writeFileSync(join(skillDir, 'SKILL.md'), skillContent);
196
+ console.log(chalk.green(` ✓ claude: .claude/skills/openspec-e2e/SKILL.md`));
197
+ }
198
+
199
+ export { claudeAdapter };
@@ -11,11 +11,12 @@ 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, installForAllEditors, installSkill, claudeAdapter } from './editors.js';
14
15
 
15
16
  const TEMPLATE_DIR = fileURLToPath(new URL('../../templates', import.meta.url));
16
17
  const SCHEMA_DIR = fileURLToPath(new URL('../../schemas', import.meta.url));
17
- const SKILL_SRC = fileURLToPath(new URL('../../.claude/skills/openspec-e2e', import.meta.url));
18
- const CMD_SRC = fileURLToPath(new URL('../../.claude/commands/opsx/e2e.md', import.meta.url));
18
+ const SKILL_SRC = fileURLToPath(new URL('../../.claude/skills/openspec-e2e/SKILL.md', import.meta.url));
19
+ const CMD_BODY_SRC = fileURLToPath(new URL('../../.claude/commands/opsx/e2e-body.md', import.meta.url));
19
20
 
20
21
  export interface InitOptions {
21
22
  change?: string;
@@ -81,14 +82,32 @@ export async function init(options: InitOptions) {
81
82
  }
82
83
  }
83
84
 
84
- // 4. Copy skill files
85
- console.log(chalk.blue('\n─── Installing Claude Code Skill ───'));
86
- await installSkill(projectRoot);
85
+ // 4. Install E2E commands for detected editors
86
+ console.log(chalk.blue('\n─── Installing E2E Commands ───'));
87
+ const detected = detectEditors(projectRoot);
88
+ if (detected.length > 0) {
89
+ const body = await readFile(CMD_BODY_SRC, 'utf-8');
90
+ installForAllEditors(body, detected, projectRoot);
91
+ } else {
92
+ const body = await readFile(CMD_BODY_SRC, 'utf-8');
93
+ installForAllEditors(body, [claudeAdapter], projectRoot);
94
+ }
87
95
 
88
- // 5. Sync Healer tools with latest @playwright/mcp
89
- console.log(chalk.blue('\n─── Syncing Healer Tools ───'));
90
- const skillDest = join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
91
- await syncMcpTools(skillDest, true);
96
+ // Claude Code also gets the SKILL.md
97
+ if (existsSync(join(projectRoot, '.claude'))) {
98
+ const skillContent = await readFile(SKILL_SRC, 'utf-8');
99
+ installSkill(projectRoot, skillContent);
100
+ }
101
+
102
+ // 5. Sync Healer tools with latest @playwright/mcp (Claude Code only)
103
+ if (existsSync(join(projectRoot, '.claude'))) {
104
+ console.log(chalk.blue('\n─── Syncing Healer Tools ───'));
105
+ const skillDest = join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
106
+ await syncMcpTools(skillDest, true);
107
+ } else {
108
+ console.log(chalk.blue('\n─── Syncing Healer Tools ───'));
109
+ console.log(chalk.gray(' - Claude Code not detected, skipping MCP sync'));
110
+ }
92
111
 
93
112
  // 6. Install OpenSpec schema
94
113
  console.log(chalk.blue('\n─── Installing OpenSpec Schema ───'));
@@ -109,8 +128,12 @@ export async function init(options: InitOptions) {
109
128
  console.log(chalk.gray(' 2. Customize tests/playwright/credentials.yaml with your test user'));
110
129
  console.log(chalk.gray(' 3. Set credentials: export E2E_USERNAME=xxx E2E_PASSWORD=yyy'));
111
130
  console.log(chalk.gray(' 4. Run auth setup: npx playwright test --project=setup'));
112
- console.log(chalk.gray(' 5. In Claude Code, run: /opsx:e2e <change-name>'));
113
- console.log(chalk.gray(' 6. Or: openspec-pw doctor to verify setup\n'));
131
+ const hasClaude = existsSync(join(projectRoot, '.claude'));
132
+ if (hasClaude) {
133
+ console.log(chalk.gray(' 5. In Claude Code, run: /opsx:e2e <change-name>'));
134
+ }
135
+ console.log(chalk.gray(` ${hasClaude ? '6.' : '5.'} Or: openspec-pw run <change-name>`));
136
+ console.log(chalk.gray(` ${hasClaude ? '7.' : '6.'} Or: openspec-pw doctor to verify setup\n`));
114
137
 
115
138
  console.log(chalk.bold('How it works:'));
116
139
  console.log(chalk.gray(' /opsx:e2e reads your OpenSpec specs and runs Playwright'));
@@ -118,24 +141,6 @@ export async function init(options: InitOptions) {
118
141
  console.log(chalk.gray(' Planner → Generator → Healer\n'));
119
142
  }
120
143
 
121
- async function installSkill(projectRoot: string) {
122
- const skillsDir = join(projectRoot, '.claude', 'skills');
123
- const skillDir = join(skillsDir, 'openspec-e2e');
124
- const cmdDir = join(projectRoot, '.claude', 'commands');
125
-
126
- // Copy skill
127
- mkdirSync(skillDir, { recursive: true });
128
- const skillContent = await readFile(SKILL_SRC + '/SKILL.md', 'utf-8');
129
- writeFileSync(join(skillDir, 'SKILL.md'), skillContent);
130
- console.log(chalk.green(` ✓ Skill installed: /openspec-e2e`));
131
-
132
- // Copy command
133
- mkdirSync(join(cmdDir, 'opsx'), { recursive: true });
134
- const cmdContent = await readFile(CMD_SRC, 'utf-8');
135
- writeFileSync(join(cmdDir, 'opsx', 'e2e.md'), cmdContent);
136
- console.log(chalk.green(` ✓ Command installed: /opsx:e2e`));
137
- }
138
-
139
144
  async function generateSeedTest(projectRoot: string) {
140
145
  const testsDir = join(projectRoot, 'tests', 'playwright');
141
146
  mkdirSync(testsDir, { recursive: true });
@@ -14,9 +14,9 @@ import { fileURLToPath } from 'url';
14
14
  import chalk from 'chalk';
15
15
  import * as tar from 'tar';
16
16
  import { syncMcpTools } from './mcpSync.js';
17
+ import { detectEditors, installForAllEditors, installSkill } from './editors.js';
17
18
 
18
- const SKILL_SRC = fileURLToPath(new URL('../../.claude/skills/openspec-e2e', import.meta.url));
19
- const CMD_SRC = fileURLToPath(new URL('../../.claude/commands/opsx', import.meta.url));
19
+ const CMD_BODY_SRC = fileURLToPath(new URL('../../.claude/commands/opsx/e2e-body.md', import.meta.url));
20
20
  const SCHEMA_DIR = fileURLToPath(new URL('../../schemas', import.meta.url));
21
21
 
22
22
  export interface UpdateOptions {
@@ -55,9 +55,9 @@ export async function update(options: UpdateOptions) {
55
55
  }
56
56
  }
57
57
 
58
- // 2. Update skill and command from npm tarball
58
+ // 2. Update commands for all detected editors + schema
59
59
  if (options.skill !== false) {
60
- console.log(chalk.blue('\n─── Updating Skill & Command ───'));
60
+ console.log(chalk.blue('\n─── Updating Commands & Schema ───'));
61
61
  try {
62
62
  const tmpDir = join(tmpdir(), 'openspec-e2e-update');
63
63
  rmSync(tmpDir, { recursive: true, force: true });
@@ -80,15 +80,30 @@ export async function update(options: UpdateOptions) {
80
80
  // Extract tarball
81
81
  await tar.extract({ file: tarballPath, cwd: tmpDir, strip: 1 });
82
82
 
83
- const skillSrc = join(tmpDir, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
84
- const cmdSrc = join(tmpDir, '.claude', 'commands', 'opsx', 'e2e.md');
83
+ const bodySrc = join(tmpDir, '.claude', 'commands', 'opsx', 'e2e-body.md');
85
84
  const schemaSrc = join(tmpDir, 'schemas', 'playwright-e2e');
86
85
 
87
- installSkillFrom(skillSrc, cmdSrc, schemaSrc, projectRoot);
86
+ // Install commands for all detected editors
87
+ const adapters = detectEditors(projectRoot);
88
+ if (adapters.length > 0 && existsSync(bodySrc)) {
89
+ const body = readFileSync(bodySrc, 'utf-8');
90
+ installForAllEditors(body, adapters, projectRoot);
91
+ }
92
+
93
+ // Install SKILL.md for Claude Code
94
+ const skillSrc = join(tmpDir, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
95
+ if (existsSync(join(projectRoot, '.claude')) && existsSync(skillSrc)) {
96
+ const skillContent = readFileSync(skillSrc, 'utf-8');
97
+ installSkill(projectRoot, skillContent);
98
+ }
99
+
100
+ // Install schema
101
+ installSchemaFrom(schemaSrc, projectRoot);
102
+
88
103
  rmSync(tmpDir, { recursive: true, force: true });
89
- console.log(chalk.green(' ✓ Skill & command updated to latest'));
104
+ console.log(chalk.green(' ✓ Commands & schema updated to latest'));
90
105
  } catch {
91
- console.log(chalk.yellow(' ⚠ Failed to update skill/command from npm'));
106
+ console.log(chalk.yellow(' ⚠ Failed to update from npm'));
92
107
  console.log(chalk.gray(' Trying npm install to pull latest version...'));
93
108
  try {
94
109
  execSync('npm install -g openspec-playwright', { stdio: 'inherit', cwd: projectRoot });
@@ -100,43 +115,24 @@ export async function update(options: UpdateOptions) {
100
115
  }
101
116
  }
102
117
 
103
- // 3. Sync Healer tools with latest @playwright/mcp
104
- console.log(chalk.blue('\n─── Syncing Healer Tools ───'));
105
- const skillDest = join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
106
- await syncMcpTools(skillDest, true);
118
+ // 3. Sync Healer tools (Claude Code only)
119
+ if (existsSync(join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md'))) {
120
+ console.log(chalk.blue('\n─── Syncing Healer Tools ───'));
121
+ const skillDest = join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
122
+ await syncMcpTools(skillDest, true);
123
+ }
107
124
 
108
125
  // Summary
109
126
  console.log(chalk.blue('\n─── Summary ───'));
110
127
  console.log(chalk.green(' ✓ Update complete!\n'));
111
128
 
112
- console.log(chalk.bold('Restart Claude Code to use the updated skill.'));
113
- console.log(chalk.gray(' Then run /opsx:e2e <change-name> to verify.\n'));
114
- }
115
-
116
- function installSkill(projectRoot: string) {
117
- installSkillFrom(
118
- join(SKILL_SRC, 'SKILL.md'),
119
- join(CMD_SRC, 'e2e.md'),
120
- join(SCHEMA_DIR, 'playwright-e2e'),
121
- projectRoot
122
- );
123
- }
124
-
125
- function installSkillFrom(skillSrc: string, cmdSrc: string, schemaSrc: string, projectRoot: string) {
126
- const skillDir = join(projectRoot, '.claude', 'skills', 'openspec-e2e');
127
- const cmdDir = join(projectRoot, '.claude', 'commands');
128
-
129
- mkdirSync(skillDir, { recursive: true });
130
- const skillContent = readFileSync(skillSrc, 'utf-8');
131
- writeFileSync(join(skillDir, 'SKILL.md'), skillContent);
132
- console.log(chalk.green(` ✓ Skill updated: /openspec-e2e`));
133
-
134
- mkdirSync(join(cmdDir, 'opsx'), { recursive: true });
135
- const cmdContent = readFileSync(cmdSrc, 'utf-8');
136
- writeFileSync(join(cmdDir, 'opsx', 'e2e.md'), cmdContent);
137
- console.log(chalk.green(` ✓ Command updated: /opsx:e2e`));
138
-
139
- installSchemaFrom(schemaSrc, projectRoot);
129
+ if (existsSync(join(projectRoot, '.claude'))) {
130
+ console.log(chalk.bold('Restart Claude Code to use the updated skill.'));
131
+ console.log(chalk.gray(' Then run /opsx:e2e <change-name> to verify.\n'));
132
+ } else {
133
+ console.log(chalk.bold('Restart your AI coding assistant to use the updated commands.'));
134
+ console.log(chalk.gray(' Then run openspec-pw run <change-name> to verify.\n'));
135
+ }
140
136
  }
141
137
 
142
138
  function installSchemaFrom(schemaSrc: string, projectRoot: string) {
Binary file