openspec-playwright 0.1.61 → 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 (52) 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.d.ts +1 -0
  22. package/dist/commands/update.js +92 -55
  23. package/dist/commands/update.js.map +1 -1
  24. package/dist/index.js +33 -26
  25. package/dist/index.js.map +1 -1
  26. package/package.json +19 -1
  27. package/schemas/playwright-e2e/templates/playwright.config.ts +22 -22
  28. package/templates/CLAUDE.md +15 -0
  29. package/templates/seed.spec.ts +5 -3
  30. package/.claude/commands/opsx/e2e-body.md +0 -39
  31. package/.claude/commands/opsx/e2e.md +0 -47
  32. package/.claude/skills/openspec-e2e/SKILL.md +0 -444
  33. package/.github/workflows/release.yml +0 -81
  34. package/docs/plans/2026-03-26-openspec-playwright-design.md +0 -180
  35. package/employee-standards.md +0 -42
  36. package/openspec/schemas/playwright-e2e/schema.yaml +0 -56
  37. package/openspec/schemas/playwright-e2e/templates/e2e-test.ts +0 -55
  38. package/openspec/schemas/playwright-e2e/templates/playwright.config.ts +0 -52
  39. package/openspec/schemas/playwright-e2e/templates/report.md +0 -27
  40. package/openspec/schemas/playwright-e2e/templates/test-plan.md +0 -24
  41. package/openspec-playwright-0.1.61.tgz +0 -0
  42. package/release-notes.md +0 -5
  43. package/src/commands/doctor.ts +0 -115
  44. package/src/commands/editors.ts +0 -606
  45. package/src/commands/init.ts +0 -252
  46. package/src/commands/mcpSync.ts +0 -160
  47. package/src/commands/run.ts +0 -172
  48. package/src/commands/update.ts +0 -165
  49. package/src/index.ts +0 -47
  50. package/tests/editors.test.ts +0 -180
  51. package/tsconfig.json +0 -18
  52. 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":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,MAAM,OAAO,CAAC;AAQ1B,MAAM,WAAW,GAAG,kBAAkB,CAAC;AAEvC,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,UAAkB,EAAE,OAAmB;IAC/D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iCAAiC,UAAU,IAAI,CAAC,CAAC,CAAC;IAEzE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAElC,6BAA6B;IAC7B,MAAM,QAAQ,GAAG,IAAI,CACnB,WAAW,EACX,OAAO,EACP,YAAY,EACZ,GAAG,UAAU,UAAU,CACxB,CAAC;IACF,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CACP,6CAA6C,UAAU,UAAU,CAClE,CACF,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,uBAAuB;IACvB,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE/D,6BAA6B;IAC7B,MAAM,SAAS,GAAG,IAAI,CACpB,WAAW,EACX,OAAO,EACP,YAAY,EACZ,kBAAkB,CACnB,CAAC;IACF,MAAM,cAAc,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CACV,iEAAiE,CAClE,CACF,CAAC;IACJ,CAAC;IAED,8CAA8C;IAC9C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAEjD,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IACxE,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,IAAI,CAAC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,UAAU,GAAG,EAAE,CAAC;IAEpB,IAAI,CAAC;QACH,yCAAyC;QACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;YACtC,GAAG,EAAE,WAAW;YAChB,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC/B,OAAO,EAAE,CAAC,OAAO,CAAC,OAAO,IAAI,GAAG,CAAC,GAAG,IAAI;SACzC,CAAC,CAAC;QACH,UAAU,GAAG,MAAM,CAAC;IACtB,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,GAA4D,CAAC;QAC3E,UAAU,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,0CAA0C;IAC1C,MAAM,OAAO,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAElD,0BAA0B;IAC1B,IACE,UAAU,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QAClD,UAAU,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QACxC,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,EAC/B,CAAC;QACD,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CACV,gEAAgE,CACjE,CACF,CAAC;IACJ,CAAC;IAED,8BAA8B;IAC9B,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9E,MAAM,UAAU,GAAG,IAAI,CACrB,WAAW,EACX,WAAW,EACX,kBAAkB,UAAU,IAAI,SAAS,KAAK,CAC/C,CAAC;IAEF,MAAM,aAAa,GAAG,cAAc,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACrE,aAAa,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IAEzC,aAAa;IACb,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAC3B;YACE,MAAM,EAAE,UAAU;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,MAAM,EAAE,UAAU;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,EAAE,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC;SACzB,EACD,IAAI,EACJ,CAAC,CACF,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxC,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,CACT,YAAY,OAAO,CAAC,KAAK,IAAI;QAC3B,KAAK,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;QAClC,IAAI;QACJ,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;YACjB,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;YAClC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACtC,eAAe,OAAO,CAAC,QAAQ,EAAE,CACpC,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,UAAU,IAAI,CAAC,CAAC,CAAC;IAEhD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,8BAA8B,OAAO,CAAC,MAAM,SAAS,CAAC,CACjE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC,CAAC;IACxD,CAAC;AACH,CAAC;AAUD,MAAM,UAAU,qBAAqB,CAAC,MAAc;IAClD,MAAM,OAAO,GAAgB;QAC3B,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,CAAC;QACT,MAAM,EAAE,CAAC;QACT,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,EAAE;KACV,CAAC;IAEF,kDAAkD;IAClD,MAAM,aAAa,GAAG,0CAA0C,CAAC;IACjE,IAAI,KAAK,CAAC;IACV,OAAO,CAAC,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;QACtD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/C,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,IAAI,MAAM,KAAK,QAAQ;YAAE,OAAO,CAAC,MAAM,EAAE,CAAC;;YACrC,OAAO,CAAC,MAAM,EAAE,CAAC;IACxB,CAAC;IAED,8DAA8D;IAC9D,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC7E,IAAI,aAAa;QAAE,OAAO,CAAC,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;IAEvD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CACrB,UAAkB,EAClB,SAAiB,EACjB,OAAoB;IAEpB,MAAM,KAAK,GAAa;QACtB,wBAAwB,UAAU,EAAE;QACpC,EAAE;QACF,iBAAiB,UAAU,IAAI;QAC/B,kBAAkB,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM;QAChE,EAAE;QACF,YAAY;QACZ,EAAE;QACF,oBAAoB;QACpB,oBAAoB;QACpB,iBAAiB,OAAO,CAAC,KAAK,IAAI;QAClC,cAAc,OAAO,CAAC,MAAM,IAAI;QAChC,cAAc,OAAO,CAAC,MAAM,IAAI;QAChC,gBAAgB,OAAO,CAAC,QAAQ,IAAI;QACpC,oBAAoB,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,IAAI;QAClE,EAAE;QACF,iBAAiB;QACjB,EAAE;KACH,CAAC;IAEF,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CACR,8DAA8D,EAC9D,EAAE,CACH,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YAClD,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC;IACrC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CACR,0CAA0C,EAC1C,iEAAiE,EACjE,mDAAmD,EACnD,qDAAqD,EACrD,sDAAsD,EACtD,EAAE,CACH,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,qCAAqC,EAAE,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -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,5 +1,6 @@
1
1
  export interface UpdateOptions {
2
2
  cli?: boolean;
3
3
  skill?: boolean;
4
+ mcp?: boolean;
4
5
  }
5
6
  export declare function update(options: UpdateOptions): Promise<void>;
@@ -1,122 +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 } 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"));
90
+ }
91
+ }
92
+ }
93
+ // 2b. Install Playwright MCP if not present (Claude Code only)
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
+ : {};
100
+ const globalMcp = claudeJson?.mcpServers ?? {};
101
+ const localMcp = claudeJson?.projects?.[projectRoot]?.mcpServers ?? {};
102
+ if (globalMcp["playwright"] || localMcp["playwright"]) {
103
+ console.log(chalk.green(" āœ“ Playwright MCP already installed"));
104
+ }
105
+ else {
106
+ try {
107
+ execSync("claude mcp add playwright npx @playwright/mcp@latest", {
108
+ cwd: projectRoot,
109
+ stdio: "inherit",
110
+ });
111
+ console.log(chalk.green(" āœ“ Playwright MCP installed globally"));
112
+ console.log(chalk.gray(" (Restart Claude Code to activate)"));
113
+ }
114
+ catch {
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)"));
87
118
  }
88
119
  }
89
120
  }
90
121
  // 3. Sync Healer tools (Claude Code only)
91
- if (existsSync(join(projectRoot, '.claude', 'skills', 'openspec-e2e', 'SKILL.md'))) {
92
- console.log(chalk.blue('\n─── Syncing Healer Tools ───'));
93
- 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");
94
125
  await syncMcpTools(skillDest, true);
95
126
  }
96
127
  // Summary
97
- console.log(chalk.blue('\n─── Summary ───'));
98
- console.log(chalk.green(' āœ“ Update complete!\n'));
99
- if (existsSync(join(projectRoot, '.claude'))) {
100
- console.log(chalk.bold('Restart Claude Code to use the updated skill.'));
101
- 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"));
102
133
  }
103
134
  else {
104
- console.log(chalk.bold('Restart your AI coding assistant to use the updated commands.'));
105
- 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"));
106
137
  }
107
138
  }
108
139
  function installSchemaFrom(schemaSrc, projectRoot) {
109
- const schemaDest = join(projectRoot, 'openspec', 'schemas', 'playwright-e2e');
140
+ const schemaDest = join(projectRoot, "openspec", "schemas", "playwright-e2e");
110
141
  mkdirSync(schemaDest, { recursive: true });
111
- const schemaYamlSrc = join(schemaSrc, 'schema.yaml');
142
+ const schemaYamlSrc = join(schemaSrc, "schema.yaml");
112
143
  if (existsSync(schemaYamlSrc)) {
113
- writeFileSync(join(schemaDest, 'schema.yaml'), readFileSync(schemaYamlSrc));
144
+ writeFileSync(join(schemaDest, "schema.yaml"), readFileSync(schemaYamlSrc));
114
145
  }
115
- const templatesSrc = join(schemaSrc, 'templates');
116
- const templatesDest = join(schemaDest, 'templates');
146
+ const templatesSrc = join(schemaSrc, "templates");
147
+ const templatesDest = join(schemaDest, "templates");
117
148
  if (existsSync(templatesSrc)) {
118
149
  mkdirSync(templatesDest, { recursive: true });
119
- 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
+ ];
120
157
  for (const file of templateFiles) {
121
158
  const src = join(templatesSrc, file);
122
159
  const dest = join(templatesDest, file);
@@ -125,6 +162,6 @@ function installSchemaFrom(schemaSrc, projectRoot) {
125
162
  }
126
163
  }
127
164
  }
128
- console.log(chalk.green(' āœ“ Schema updated: openspec/schemas/playwright-e2e/'));
165
+ console.log(chalk.green(" āœ“ Schema updated: openspec/schemas/playwright-e2e/"));
129
166
  }
130
167
  //# sourceMappingURL=update.js.map