openspec-playwright 0.1.62 → 0.1.64

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 (55) hide show
  1. package/.claude/commands/CLAUDE.md +12 -0
  2. package/.claude/commands/opsx/CLAUDE.md +12 -0
  3. package/.claude/commands/opsx/e2e-body.md +5 -0
  4. package/.claude/commands/opsx/e2e.md +5 -1
  5. package/.claude/skills/CLAUDE.md +12 -0
  6. package/.claude/skills/openspec-e2e/CLAUDE.md +14 -0
  7. package/.claude/skills/openspec-e2e/SKILL.md +101 -77
  8. package/LICENSE +21 -0
  9. package/README.md +4 -3
  10. package/README.zh-CN.md +4 -3
  11. package/bin/CLAUDE.md +11 -0
  12. package/dist/CLAUDE.md +17 -0
  13. package/dist/commands/doctor.d.ts +4 -1
  14. package/dist/commands/doctor.js +110 -73
  15. package/dist/commands/doctor.js.map +1 -1
  16. package/dist/commands/editors.js +149 -95
  17. package/dist/commands/editors.js.map +1 -1
  18. package/dist/commands/init.js +105 -97
  19. package/dist/commands/init.js.map +1 -1
  20. package/dist/commands/mcpSync.js +46 -31
  21. package/dist/commands/mcpSync.js.map +1 -1
  22. package/dist/commands/run.d.ts +13 -0
  23. package/dist/commands/run.js +74 -51
  24. package/dist/commands/run.js.map +1 -1
  25. package/dist/commands/uninstall.d.ts +1 -0
  26. package/dist/commands/uninstall.js +133 -0
  27. package/dist/commands/uninstall.js.map +1 -0
  28. package/dist/commands/update.js +79 -68
  29. package/dist/commands/update.js.map +1 -1
  30. package/dist/index.js +33 -26
  31. package/dist/index.js.map +1 -1
  32. package/employee-standards.md +3 -3
  33. package/package.json +21 -1
  34. package/schemas/playwright-e2e/templates/playwright.config.ts +22 -22
  35. package/templates/CLAUDE.md +15 -0
  36. package/templates/seed.spec.ts +5 -3
  37. package/.github/workflows/release.yml +0 -81
  38. package/docs/plans/2026-03-26-openspec-playwright-design.md +0 -180
  39. package/openspec/schemas/playwright-e2e/schema.yaml +0 -56
  40. package/openspec/schemas/playwright-e2e/templates/e2e-test.ts +0 -55
  41. package/openspec/schemas/playwright-e2e/templates/playwright.config.ts +0 -52
  42. package/openspec/schemas/playwright-e2e/templates/report.md +0 -27
  43. package/openspec/schemas/playwright-e2e/templates/test-plan.md +0 -24
  44. package/openspec-playwright-0.1.62.tgz +0 -0
  45. package/release-notes.md +0 -5
  46. package/src/commands/doctor.ts +0 -115
  47. package/src/commands/editors.ts +0 -606
  48. package/src/commands/init.ts +0 -252
  49. package/src/commands/mcpSync.ts +0 -160
  50. package/src/commands/run.ts +0 -172
  51. package/src/commands/update.ts +0 -192
  52. package/src/index.ts +0 -47
  53. package/tests/editors.test.ts +0 -180
  54. package/tsconfig.json +0 -18
  55. package/vitest.config.ts +0 -9
@@ -1,88 +1,111 @@
1
- import { execSync } from 'child_process';
2
- import { existsSync, mkdirSync, writeFileSync } from 'fs';
3
- import { join } from 'path';
4
- import chalk from 'chalk';
5
- const REPORTS_DIR = 'openspec/reports';
1
+ import { execSync } from "child_process";
2
+ import { existsSync, mkdirSync, writeFileSync } from "fs";
3
+ import { join } from "path";
4
+ import chalk from "chalk";
5
+ const REPORTS_DIR = "openspec/reports";
6
6
  export async function run(changeName, options) {
7
7
  console.log(chalk.blue(`\nšŸ” OpenSpec Playwright E2E: ${changeName}\n`));
8
8
  const projectRoot = process.cwd();
9
9
  // 1. Verify test file exists
10
- const testFile = join(projectRoot, 'tests', 'playwright', `${changeName}.spec.ts`);
10
+ const testFile = join(projectRoot, "tests", "playwright", `${changeName}.spec.ts`);
11
11
  if (!existsSync(testFile)) {
12
12
  console.log(chalk.red(` āœ— Test file not found: tests/playwright/${changeName}.spec.ts`));
13
- console.log(chalk.gray(' Run /opsx:e2e first to generate tests.\n'));
13
+ console.log(chalk.gray(" Run /opsx:e2e first to generate tests.\n"));
14
14
  process.exit(1);
15
15
  }
16
16
  // 2. Setup reports dir
17
17
  mkdirSync(join(projectRoot, REPORTS_DIR), { recursive: true });
18
18
  // 3. Detect auth credentials
19
- const credsPath = join(projectRoot, 'tests', 'playwright', 'credentials.yaml');
19
+ const credsPath = join(projectRoot, "tests", "playwright", "credentials.yaml");
20
20
  const hasCredentials = existsSync(credsPath);
21
21
  if (!hasCredentials) {
22
- console.log(chalk.yellow(' ⚠ No credentials.yaml found — tests may fail if auth required'));
22
+ console.log(chalk.yellow(" ⚠ No credentials.yaml found — tests may fail if auth required"));
23
23
  }
24
24
  // 4. Run Playwright tests with output capture
25
- console.log(chalk.blue('─── Running Tests ───'));
26
- const args = ['npx', 'playwright', 'test', testFile, '--reporter=list'];
25
+ console.log(chalk.blue("─── Running Tests ───"));
26
+ const args = ["npx", "playwright", "test", testFile, "--reporter=list"];
27
27
  if (options.project) {
28
- args.push('--project=' + options.project);
28
+ args.push("--project=" + options.project);
29
29
  }
30
- let testOutput = '';
31
- let exitCode = 0;
30
+ let testOutput = "";
32
31
  try {
33
32
  // Capture stdout to detect port mismatch
34
- const result = execSync(args.join(' '), {
33
+ const result = execSync(args.join(" "), {
35
34
  cwd: projectRoot,
36
- encoding: 'utf-8',
37
- stdio: ['pipe', 'pipe', 'pipe'],
35
+ encoding: "utf-8",
36
+ stdio: ["pipe", "pipe", "pipe"],
38
37
  timeout: (options.timeout ?? 300) * 1000,
39
38
  });
40
39
  testOutput = result;
41
40
  }
42
41
  catch (err) {
43
- exitCode = 1;
44
42
  const error = err;
45
- testOutput = (error.stdout ?? '') + (error.stderr ?? '');
43
+ testOutput = (error.stdout ?? "") + (error.stderr ?? "");
46
44
  }
47
45
  // 5. Parse results from Playwright output
48
46
  const results = parsePlaywrightOutput(testOutput);
49
47
  // 6. Detect port mismatch
50
- if (testOutput.includes('net::ERR_CONNECTION_REFUSED') ||
51
- testOutput.includes('listen EADDRINUSE') ||
52
- testOutput.includes('0.0.0.0:')) {
53
- console.log(chalk.yellow(' ⚠ Port mismatch detected. Check BASE_URL and webServer port.'));
48
+ if (testOutput.includes("net::ERR_CONNECTION_REFUSED") ||
49
+ testOutput.includes("listen EADDRINUSE") ||
50
+ testOutput.includes("0.0.0.0:")) {
51
+ console.log(chalk.yellow(" ⚠ Port mismatch detected. Check BASE_URL and webServer port."));
54
52
  }
55
53
  // 7. Generate markdown report
56
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
54
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
57
55
  const reportPath = join(projectRoot, REPORTS_DIR, `playwright-e2e-${changeName}-${timestamp}.md`);
58
56
  const reportContent = generateReport(changeName, timestamp, results);
59
57
  writeFileSync(reportPath, reportContent);
60
58
  // 8. Summary
61
- console.log(chalk.blue('\n─── Results ───'));
59
+ if (options.json) {
60
+ const output = JSON.stringify({
61
+ change: changeName,
62
+ total: results.total,
63
+ passed: results.passed,
64
+ failed: results.failed,
65
+ duration: results.duration,
66
+ report: reportPath,
67
+ tests: results.tests,
68
+ ok: results.failed === 0,
69
+ }, null, 2);
70
+ console.log(output);
71
+ if (results.failed > 0)
72
+ process.exit(1);
73
+ return;
74
+ }
75
+ console.log(chalk.blue("\n─── Results ───"));
62
76
  console.log(` Tests: ${results.total} ` +
63
- chalk.green(`āœ“ ${results.passed}`) + ' ' +
64
- (results.failed > 0 ? chalk.red(`āœ— ${results.failed}`) : chalk.gray(`āœ— ${results.failed}`)) +
77
+ chalk.green(`āœ“ ${results.passed}`) +
78
+ " " +
79
+ (results.failed > 0
80
+ ? chalk.red(`āœ— ${results.failed}`)
81
+ : chalk.gray(`āœ— ${results.failed}`)) +
65
82
  ` Duration: ${results.duration}`);
66
- console.log(chalk.blue('\n─── Report ───'));
83
+ console.log(chalk.blue("\n─── Report ───"));
67
84
  console.log(chalk.green(` āœ“ ${reportPath}\n`));
68
85
  if (results.failed > 0) {
69
86
  console.log(chalk.red(`āœ— E2E verification FAILED (${results.failed} tests)`));
70
87
  process.exit(1);
71
88
  }
72
89
  else {
73
- console.log(chalk.green('āœ“ E2E verification PASSED'));
90
+ console.log(chalk.green("āœ“ E2E verification PASSED"));
74
91
  }
75
92
  }
76
- function parsePlaywrightOutput(output) {
77
- const results = { total: 0, passed: 0, failed: 0, duration: '0s', tests: [] };
93
+ export function parsePlaywrightOutput(output) {
94
+ const results = {
95
+ total: 0,
96
+ passed: 0,
97
+ failed: 0,
98
+ duration: "0s",
99
+ tests: [],
100
+ };
78
101
  // Parse: "āœ“ my-test (1.2s)" or "āœ— my-test (0.5s)"
79
102
  const testLineRegex = /([āœ“āœ—x]) (.+?) \((\d+(?:\.\d+)?[a-z]+)\)/g;
80
103
  let match;
81
104
  while ((match = testLineRegex.exec(output)) !== null) {
82
- const status = match[1] === 'āœ“' ? 'passed' : 'failed';
105
+ const status = match[1] === "āœ“" ? "passed" : "failed";
83
106
  results.tests.push({ name: match[2], status });
84
107
  results.total++;
85
- if (status === 'passed')
108
+ if (status === "passed")
86
109
  results.passed++;
87
110
  else
88
111
  results.failed++;
@@ -96,40 +119,40 @@ function parsePlaywrightOutput(output) {
96
119
  function generateReport(changeName, timestamp, results) {
97
120
  const lines = [
98
121
  `# E2E Verify Report: ${changeName}`,
99
- '',
122
+ "",
100
123
  `**Change**: \`${changeName}\``,
101
- `**Generated**: ${timestamp.replace('T', ' ').slice(0, 16)} UTC`,
102
- '',
103
- '## Summary',
104
- '',
105
- '| Check | Status |',
106
- '|-------|--------|',
124
+ `**Generated**: ${timestamp.replace("T", " ").slice(0, 16)} UTC`,
125
+ "",
126
+ "## Summary",
127
+ "",
128
+ "| Check | Status |",
129
+ "|-------|--------|",
107
130
  `| Tests Run | ${results.total} |`,
108
131
  `| Passed | ${results.passed} |`,
109
132
  `| Failed | ${results.failed} |`,
110
133
  `| Duration | ${results.duration} |`,
111
- `| Final Status | ${results.failed === 0 ? 'āœ… PASS' : 'āŒ FAIL'} |`,
112
- '',
113
- '## Test Results',
114
- '',
134
+ `| Final Status | ${results.failed === 0 ? "āœ… PASS" : "āŒ FAIL"} |`,
135
+ "",
136
+ "## Test Results",
137
+ "",
115
138
  ];
116
139
  if (results.tests.length === 0) {
117
- lines.push('_(No test output captured — check Playwright configuration)_', '');
140
+ lines.push("_(No test output captured — check Playwright configuration)_", "");
118
141
  }
119
142
  else {
120
143
  for (const test of results.tests) {
121
- const icon = test.status === 'passed' ? 'āœ…' : 'āŒ';
144
+ const icon = test.status === "passed" ? "āœ…" : "āŒ";
122
145
  lines.push(`- ${test.name}: ${icon} ${test.status}`);
123
146
  }
124
- lines.push('');
147
+ lines.push("");
125
148
  }
126
- lines.push('## Recommendations', '');
149
+ lines.push("## Recommendations", "");
127
150
  if (results.failed > 0) {
128
- lines.push('Review failed tests above. Common fixes:', '- Update selectors if UI changed (use `data-testid` attributes)', '- Adjust BASE_URL in seed.spec.ts if port differs', '- Set E2E_USERNAME/E2E_PASSWORD if auth is required', '- Check `npx playwright show-report` for screenshots', '');
151
+ lines.push("Review failed tests above. Common fixes:", "- Update selectors if UI changed (use `data-testid` attributes)", "- Adjust BASE_URL in seed.spec.ts if port differs", "- Set E2E_USERNAME/E2E_PASSWORD if auth is required", "- Check `npx playwright show-report` for screenshots", "");
129
152
  }
130
153
  else {
131
- lines.push('All tests passed. No action needed.', '');
154
+ lines.push("All tests passed. No action needed.", "");
132
155
  }
133
- return lines.join('\n');
156
+ return lines.join("\n");
134
157
  }
135
158
  //# sourceMappingURL=run.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function uninstall(): Promise<void>;
@@ -0,0 +1,133 @@
1
+ import { existsSync, readFileSync, writeFileSync, rmSync, readdirSync, rmdirSync, } from "fs";
2
+ import { join, dirname } from "path";
3
+ import { homedir } from "os";
4
+ import chalk from "chalk";
5
+ import { detectEditors, detectCodex } from "./editors.js";
6
+ export async function uninstall() {
7
+ console.log(chalk.blue("\nšŸ—‘ļø Uninstalling OpenSpec + Playwright E2E\n"));
8
+ const projectRoot = process.cwd();
9
+ // 1. Remove Playwright MCP from .claude.json
10
+ console.log(chalk.blue("─── Removing Playwright MCP ───"));
11
+ removeMcpFromClaudeJson(homedir(), projectRoot);
12
+ // 2. Remove E2E commands for detected editors
13
+ console.log(chalk.blue("\n─── Removing E2E Commands ───"));
14
+ const detected = detectEditors(projectRoot);
15
+ const codex = detectCodex();
16
+ const adapters = codex ? [...detected, codex] : detected;
17
+ if (adapters.length > 0) {
18
+ for (const adapter of adapters) {
19
+ const relPath = adapter.getCommandPath("e2e");
20
+ const absPath = join(projectRoot, relPath);
21
+ if (existsSync(absPath)) {
22
+ rmSync(absPath);
23
+ // Remove empty parent directories
24
+ cleanupEmptyDirs(dirname(absPath), projectRoot);
25
+ console.log(chalk.green(` āœ“ ${adapter.toolId}: removed ${relPath}`));
26
+ }
27
+ }
28
+ }
29
+ else {
30
+ console.log(chalk.gray(" - No editors detected, skipping"));
31
+ }
32
+ // 3. Remove SKILL.md
33
+ console.log(chalk.blue("\n─── Removing Skill ───"));
34
+ const skillDir = join(projectRoot, ".claude", "skills", "openspec-e2e");
35
+ if (existsSync(skillDir)) {
36
+ rmSync(skillDir, { recursive: true, force: true });
37
+ console.log(chalk.green(" āœ“ Removed .claude/skills/openspec-e2e/"));
38
+ }
39
+ else {
40
+ console.log(chalk.gray(" - Skill not found, skipping"));
41
+ }
42
+ // 4. Remove schema
43
+ console.log(chalk.blue("\n─── Removing Schema ───"));
44
+ const schemaDir = join(projectRoot, "openspec", "schemas", "playwright-e2e");
45
+ if (existsSync(schemaDir)) {
46
+ rmSync(schemaDir, { recursive: true, force: true });
47
+ console.log(chalk.green(" āœ“ Removed openspec/schemas/playwright-e2e/"));
48
+ }
49
+ else {
50
+ console.log(chalk.gray(" - Schema not found, skipping"));
51
+ }
52
+ // 5. Clean CLAUDE.md markers
53
+ console.log(chalk.blue("\n─── Cleaning CLAUDE.md ───"));
54
+ cleanClaudeMd(projectRoot);
55
+ // Summary
56
+ console.log(chalk.blue("\n─── Summary ───"));
57
+ console.log(chalk.green(" āœ“ Uninstall complete!\n"));
58
+ console.log(chalk.gray(" Note: Run openspec-pw doctor to verify clean removal.\n"));
59
+ }
60
+ function removeMcpFromClaudeJson(homeDir, projectRoot) {
61
+ const claudeJsonPath = join(homeDir, ".claude.json");
62
+ if (!existsSync(claudeJsonPath)) {
63
+ console.log(chalk.gray(" - .claude.json not found, skipping"));
64
+ return;
65
+ }
66
+ try {
67
+ const content = readFileSync(claudeJsonPath, "utf-8");
68
+ const json = JSON.parse(content);
69
+ let changed = false;
70
+ // Remove from global mcpServers
71
+ if (json.mcpServers?.["playwright"]) {
72
+ delete json.mcpServers["playwright"];
73
+ changed = true;
74
+ }
75
+ // Remove from project-level mcpServers
76
+ if (json.projects?.[projectRoot]?.mcpServers?.["playwright"]) {
77
+ delete json.projects[projectRoot].mcpServers["playwright"];
78
+ changed = true;
79
+ }
80
+ if (changed) {
81
+ writeFileSync(claudeJsonPath, JSON.stringify(json, null, 2) + "\n");
82
+ console.log(chalk.green(" āœ“ Removed playwright from .claude.json"));
83
+ console.log(chalk.gray(" Restart Claude Code to complete removal"));
84
+ }
85
+ else {
86
+ console.log(chalk.gray(" - Playwright MCP not found in .claude.json"));
87
+ }
88
+ }
89
+ catch (err) {
90
+ console.log(chalk.yellow(` ⚠ Failed to update .claude.json: ${err instanceof Error ? err.message : String(err)}`));
91
+ }
92
+ }
93
+ function cleanupEmptyDirs(dir, stopAt) {
94
+ while (dir !== stopAt && dir.length > stopAt.length) {
95
+ try {
96
+ const entries = readdirSync(dir);
97
+ if (entries.length === 0) {
98
+ rmdirSync(dir);
99
+ dir = dirname(dir);
100
+ }
101
+ else {
102
+ break;
103
+ }
104
+ }
105
+ catch {
106
+ break;
107
+ }
108
+ }
109
+ }
110
+ function cleanClaudeMd(projectRoot) {
111
+ const dest = join(projectRoot, "CLAUDE.md");
112
+ if (!existsSync(dest)) {
113
+ console.log(chalk.gray(" - CLAUDE.md not found, skipping"));
114
+ return;
115
+ }
116
+ const existing = readFileSync(dest, "utf-8");
117
+ const markerStart = "<!-- OPENSPEC:START -->";
118
+ const markerEnd = "<!-- OPENSPEC:END -->";
119
+ if (!existing.includes(markerStart)) {
120
+ console.log(chalk.gray(" - No OpenSpec markers found in CLAUDE.md"));
121
+ return;
122
+ }
123
+ const updated = existing
124
+ .split("\n")
125
+ .filter((line) => !line.trim().startsWith(markerStart) &&
126
+ !line.trim().startsWith(markerEnd))
127
+ .join("\n")
128
+ .replace(/\n{3,}/g, "\n\n")
129
+ .trim() + "\n";
130
+ writeFileSync(dest, updated);
131
+ console.log(chalk.green(" āœ“ Removed OpenSpec markers from CLAUDE.md"));
132
+ }
133
+ //# sourceMappingURL=uninstall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.js","sourceRoot":"","sources":["../../src/commands/uninstall.ts"],"names":[],"mappings":"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"}
@@ -1,148 +1,159 @@
1
- import { execSync, exec } from 'child_process';
2
- import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, readdirSync, statSync, } from 'fs';
3
- import { join } from 'path';
4
- import { tmpdir, homedir } from 'os';
5
- import { promisify } from 'util';
6
- import { fileURLToPath } from 'url';
7
- import chalk from 'chalk';
8
- import * as tar from 'tar';
9
- import { syncMcpTools } from './mcpSync.js';
10
- import { detectEditors, detectCodex, installForAllEditors, installSkill } from './editors.js';
11
- const CMD_BODY_SRC = fileURLToPath(new URL('../../.claude/commands/opsx/e2e-body.md', import.meta.url));
12
- const SCHEMA_DIR = fileURLToPath(new URL('../../schemas', import.meta.url));
1
+ import { execSync, exec } from "child_process";
2
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, readdirSync, statSync, } from "fs";
3
+ import { join } from "path";
4
+ import { tmpdir, homedir } from "os";
5
+ import { promisify } from "util";
6
+ import chalk from "chalk";
7
+ import * as tar from "tar";
8
+ import { syncMcpTools } from "./mcpSync.js";
9
+ import { detectEditors, detectCodex, installForAllEditors, installSkill, } from "./editors.js";
13
10
  export async function update(options) {
14
- console.log(chalk.blue('\nšŸ”„ Updating OpenSpec + Playwright E2E\n'));
11
+ console.log(chalk.blue("\nšŸ”„ Updating OpenSpec + Playwright E2E\n"));
15
12
  const projectRoot = process.cwd();
16
13
  // Check if init has been run
17
- const hasSkill = existsSync(join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md'));
18
- const hasOpenSpec = existsSync(join(projectRoot, 'openspec'));
14
+ const hasSkill = existsSync(join(projectRoot, ".claude", "skills", "openspec-e2e", "SKILL.md"));
15
+ const hasOpenSpec = existsSync(join(projectRoot, "openspec"));
19
16
  if (!hasSkill && !hasOpenSpec) {
20
- console.log(chalk.yellow(' ⚠ OpenSpec + Playwright E2E not initialized.'));
17
+ console.log(chalk.yellow(" ⚠ OpenSpec + Playwright E2E not initialized."));
21
18
  console.log(chalk.gray(' Run "openspec-pw init" first to set up the integration.\n'));
22
19
  return;
23
20
  }
24
21
  // 1. Update CLI tool from npm
25
22
  if (options.cli !== false) {
26
- console.log(chalk.blue('─── Updating CLI ───'));
23
+ console.log(chalk.blue("─── Updating CLI ───"));
27
24
  try {
28
- execSync('npm install -g openspec-playwright', { stdio: 'inherit', cwd: projectRoot });
29
- console.log(chalk.green(' āœ“ CLI updated via npm'));
25
+ execSync("npm install -g openspec-playwright", {
26
+ stdio: "inherit",
27
+ cwd: projectRoot,
28
+ });
29
+ console.log(chalk.green(" āœ“ CLI updated via npm"));
30
30
  }
31
31
  catch {
32
- console.log(chalk.yellow(' ⚠ Failed to update CLI via npm'));
33
- console.log(chalk.gray(' Run manually: npm install -g openspec-playwright'));
32
+ console.log(chalk.yellow(" ⚠ Failed to update CLI via npm"));
33
+ console.log(chalk.gray(" Run manually: npm install -g openspec-playwright"));
34
34
  }
35
35
  }
36
36
  // 2. Update commands for all detected editors + schema
37
37
  if (options.skill !== false) {
38
- console.log(chalk.blue('\n─── Updating Commands & Schema ───'));
38
+ console.log(chalk.blue("\n─── Updating Commands & Schema ───"));
39
39
  try {
40
- const tmpDir = join(tmpdir(), 'openspec-e2e-update');
40
+ const tmpDir = join(tmpdir(), "openspec-e2e-update");
41
41
  rmSync(tmpDir, { recursive: true, force: true });
42
42
  mkdirSync(tmpDir, { recursive: true });
43
43
  const execAsync = promisify(exec);
44
44
  await execAsync(`npm pack openspec-playwright --pack-destination ${tmpDir}`, { timeout: 30000 });
45
45
  // Find the latest tarball by mtime
46
46
  const tgzFiles = readdirSync(tmpDir)
47
- .filter(f => f.startsWith('openspec-playwright-') && f.endsWith('.tgz'))
48
- .map(f => ({ name: f, mtime: statSync(join(tmpDir, f)).mtimeMs }))
47
+ .filter((f) => f.startsWith("openspec-playwright-") && f.endsWith(".tgz"))
48
+ .map((f) => ({ name: f, mtime: statSync(join(tmpDir, f)).mtimeMs }))
49
49
  .sort((a, b) => b.mtime - a.mtime);
50
50
  if (tgzFiles.length === 0)
51
- throw new Error('No tarball found');
51
+ throw new Error("No tarball found");
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 bodySrc = join(tmpDir, '.claude', 'commands', 'opsx', 'e2e-body.md');
56
- const schemaSrc = join(tmpDir, 'schemas', 'playwright-e2e');
55
+ const bodySrc = join(tmpDir, ".claude", "commands", "opsx", "e2e-body.md");
56
+ const schemaSrc = join(tmpDir, "schemas", "playwright-e2e");
57
57
  // Install commands for all detected editors
58
58
  const detected = detectEditors(projectRoot);
59
59
  const codex = detectCodex();
60
60
  const adapters = codex ? [...detected, codex] : detected;
61
61
  if (adapters.length > 0 && existsSync(bodySrc)) {
62
- const body = readFileSync(bodySrc, 'utf-8');
62
+ const body = readFileSync(bodySrc, "utf-8");
63
63
  installForAllEditors(body, adapters, projectRoot);
64
64
  }
65
65
  // Install SKILL.md for Claude Code
66
- const skillSrc = join(tmpDir, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
67
- if (existsSync(join(projectRoot, '.claude')) && existsSync(skillSrc)) {
68
- const skillContent = readFileSync(skillSrc, 'utf-8');
66
+ const skillSrc = join(tmpDir, ".claude", "skills", "openspec-e2e", "SKILL.md");
67
+ if (existsSync(join(projectRoot, ".claude")) && existsSync(skillSrc)) {
68
+ const skillContent = readFileSync(skillSrc, "utf-8");
69
69
  installSkill(projectRoot, skillContent);
70
70
  }
71
71
  // Install schema
72
72
  installSchemaFrom(schemaSrc, projectRoot);
73
73
  rmSync(tmpDir, { recursive: true, force: true });
74
- console.log(chalk.green(' āœ“ Commands & schema updated to latest'));
74
+ console.log(chalk.green(" āœ“ Commands & schema updated to latest"));
75
75
  }
76
76
  catch (err) {
77
77
  const msg = err instanceof Error ? err.message : String(err);
78
78
  console.log(chalk.yellow(` ⚠ Failed to update from npm: ${msg}`));
79
- console.log(chalk.gray(' Trying npm install to pull latest version...'));
79
+ console.log(chalk.gray(" Trying npm install to pull latest version..."));
80
80
  try {
81
- execSync('npm install -g openspec-playwright', { stdio: 'inherit', cwd: projectRoot });
82
- console.log(chalk.green(' āœ“ Updated via npm install'));
81
+ execSync("npm install -g openspec-playwright", {
82
+ stdio: "inherit",
83
+ cwd: projectRoot,
84
+ });
85
+ console.log(chalk.green(" āœ“ Updated via npm install"));
83
86
  }
84
87
  catch {
85
- console.log(chalk.red(' āœ— Failed to update. Run manually:'));
86
- console.log(chalk.gray(' npm install -g openspec-playwright'));
88
+ console.log(chalk.red(" āœ— Failed to update. Run manually:"));
89
+ console.log(chalk.gray(" npm install -g openspec-playwright"));
87
90
  }
88
91
  }
89
92
  }
90
93
  // 2b. Install Playwright MCP if not present (Claude Code only)
91
- if (options.mcp !== false && existsSync(join(projectRoot, '.claude'))) {
92
- console.log(chalk.blue('\n─── Installing Playwright MCP ───'));
93
- const claudeJsonPath = join(homedir(), '.claude.json');
94
- const claudeJson = existsSync(claudeJsonPath) ? JSON.parse(readFileSync(claudeJsonPath, 'utf-8')) : {};
94
+ if (options.mcp !== false && existsSync(join(projectRoot, ".claude"))) {
95
+ console.log(chalk.blue("\n─── Installing Playwright MCP ───"));
96
+ const claudeJsonPath = join(homedir(), ".claude.json");
97
+ const claudeJson = existsSync(claudeJsonPath)
98
+ ? JSON.parse(readFileSync(claudeJsonPath, "utf-8"))
99
+ : {};
95
100
  const globalMcp = claudeJson?.mcpServers ?? {};
96
101
  const localMcp = claudeJson?.projects?.[projectRoot]?.mcpServers ?? {};
97
- if (globalMcp['playwright'] || localMcp['playwright']) {
98
- console.log(chalk.green(' āœ“ Playwright MCP already installed'));
102
+ if (globalMcp["playwright"] || localMcp["playwright"]) {
103
+ console.log(chalk.green(" āœ“ Playwright MCP already installed"));
99
104
  }
100
105
  else {
101
106
  try {
102
- execSync('claude mcp add playwright npx @playwright/mcp@latest', {
107
+ execSync("claude mcp add playwright npx @playwright/mcp@latest", {
103
108
  cwd: projectRoot,
104
- stdio: 'inherit',
109
+ stdio: "inherit",
105
110
  });
106
- console.log(chalk.green(' āœ“ Playwright MCP installed globally'));
107
- console.log(chalk.gray(' (Restart Claude Code to activate)'));
111
+ console.log(chalk.green(" āœ“ Playwright MCP installed globally"));
112
+ console.log(chalk.gray(" (Restart Claude Code to activate)"));
108
113
  }
109
114
  catch {
110
- console.log(chalk.yellow(' ⚠ Failed to install Playwright MCP'));
111
- console.log(chalk.gray(' Run manually: claude mcp add playwright npx @playwright/mcp@latest'));
112
- console.log(chalk.gray(' (Restart Claude Code to activate the MCP server)'));
115
+ console.log(chalk.yellow(" ⚠ Failed to install Playwright MCP"));
116
+ console.log(chalk.gray(" Run manually: claude mcp add playwright npx @playwright/mcp@latest"));
117
+ console.log(chalk.gray(" (Restart Claude Code to activate the MCP server)"));
113
118
  }
114
119
  }
115
120
  }
116
121
  // 3. Sync Healer tools (Claude Code only)
117
- if (existsSync(join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md'))) {
118
- console.log(chalk.blue('\n─── Syncing Healer Tools ───'));
119
- const skillDest = join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md');
122
+ if (existsSync(join(projectRoot, ".claude", "skills", "openspec-e2e", "SKILL.md"))) {
123
+ console.log(chalk.blue("\n─── Syncing Healer Tools ───"));
124
+ const skillDest = join(projectRoot, ".claude", "skills", "openspec-e2e", "SKILL.md");
120
125
  await syncMcpTools(skillDest, true);
121
126
  }
122
127
  // Summary
123
- console.log(chalk.blue('\n─── Summary ───'));
124
- console.log(chalk.green(' āœ“ Update complete!\n'));
125
- if (existsSync(join(projectRoot, '.claude'))) {
126
- console.log(chalk.bold('Restart Claude Code to use the updated skill.'));
127
- console.log(chalk.gray(' Then run /opsx:e2e <change-name> to verify.\n'));
128
+ console.log(chalk.blue("\n─── Summary ───"));
129
+ console.log(chalk.green(" āœ“ Update complete!\n"));
130
+ if (existsSync(join(projectRoot, ".claude"))) {
131
+ console.log(chalk.bold("Restart Claude Code to use the updated skill."));
132
+ console.log(chalk.gray(" Then run /opsx:e2e <change-name> to verify.\n"));
128
133
  }
129
134
  else {
130
- console.log(chalk.bold('Restart your AI coding assistant to use the updated commands.'));
131
- console.log(chalk.gray(' Then run openspec-pw run <change-name> to verify.\n'));
135
+ console.log(chalk.bold("Restart your AI coding assistant to use the updated commands."));
136
+ console.log(chalk.gray(" Then run openspec-pw run <change-name> to verify.\n"));
132
137
  }
133
138
  }
134
139
  function installSchemaFrom(schemaSrc, projectRoot) {
135
- const schemaDest = join(projectRoot, 'openspec', 'schemas', 'playwright-e2e');
140
+ const schemaDest = join(projectRoot, "openspec", "schemas", "playwright-e2e");
136
141
  mkdirSync(schemaDest, { recursive: true });
137
- const schemaYamlSrc = join(schemaSrc, 'schema.yaml');
142
+ const schemaYamlSrc = join(schemaSrc, "schema.yaml");
138
143
  if (existsSync(schemaYamlSrc)) {
139
- writeFileSync(join(schemaDest, 'schema.yaml'), readFileSync(schemaYamlSrc));
144
+ writeFileSync(join(schemaDest, "schema.yaml"), readFileSync(schemaYamlSrc));
140
145
  }
141
- const templatesSrc = join(schemaSrc, 'templates');
142
- const templatesDest = join(schemaDest, 'templates');
146
+ const templatesSrc = join(schemaSrc, "templates");
147
+ const templatesDest = join(schemaDest, "templates");
143
148
  if (existsSync(templatesSrc)) {
144
149
  mkdirSync(templatesDest, { recursive: true });
145
- const templateFiles = ['test-plan.md', 'report.md', 'e2e-test.ts', 'playwright.config.ts', 'app-knowledge.md'];
150
+ const templateFiles = [
151
+ "test-plan.md",
152
+ "report.md",
153
+ "e2e-test.ts",
154
+ "playwright.config.ts",
155
+ "app-knowledge.md",
156
+ ];
146
157
  for (const file of templateFiles) {
147
158
  const src = join(templatesSrc, file);
148
159
  const dest = join(templatesDest, file);
@@ -151,6 +162,6 @@ function installSchemaFrom(schemaSrc, projectRoot) {
151
162
  }
152
163
  }
153
164
  }
154
- console.log(chalk.green(' āœ“ Schema updated: openspec/schemas/playwright-e2e/'));
165
+ console.log(chalk.green(" āœ“ Schema updated: openspec/schemas/playwright-e2e/"));
155
166
  }
156
167
  //# sourceMappingURL=update.js.map