@kosuke-ai/cli 0.0.12 → 0.0.14

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/dist/index.d.ts +14 -6
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +148 -6
  4. package/dist/index.js.map +1 -1
  5. package/dist/kosuke/commands/build.d.ts +22 -0
  6. package/dist/kosuke/commands/build.d.ts.map +1 -0
  7. package/dist/kosuke/commands/build.js +135 -0
  8. package/dist/kosuke/commands/build.js.map +1 -0
  9. package/dist/kosuke/commands/review.d.ts +21 -0
  10. package/dist/kosuke/commands/review.d.ts.map +1 -0
  11. package/dist/kosuke/commands/review.js +185 -0
  12. package/dist/kosuke/commands/review.js.map +1 -0
  13. package/dist/kosuke/commands/ship.d.ts +23 -0
  14. package/dist/kosuke/commands/ship.d.ts.map +1 -0
  15. package/dist/kosuke/commands/ship.js +419 -0
  16. package/dist/kosuke/commands/ship.js.map +1 -0
  17. package/dist/kosuke/commands/test.d.ts +27 -0
  18. package/dist/kosuke/commands/test.d.ts.map +1 -0
  19. package/dist/kosuke/commands/test.js +338 -0
  20. package/dist/kosuke/commands/test.js.map +1 -0
  21. package/dist/kosuke/types.d.ts +82 -2
  22. package/dist/kosuke/types.d.ts.map +1 -1
  23. package/dist/kosuke/utils/error-analyzer.d.ts +32 -0
  24. package/dist/kosuke/utils/error-analyzer.d.ts.map +1 -0
  25. package/dist/kosuke/utils/error-analyzer.js +129 -0
  26. package/dist/kosuke/utils/error-analyzer.js.map +1 -0
  27. package/dist/kosuke/utils/git.d.ts +12 -0
  28. package/dist/kosuke/utils/git.d.ts.map +1 -1
  29. package/dist/kosuke/utils/git.js +39 -0
  30. package/dist/kosuke/utils/git.js.map +1 -1
  31. package/dist/kosuke/utils/log-collector.d.ts +81 -0
  32. package/dist/kosuke/utils/log-collector.d.ts.map +1 -0
  33. package/dist/kosuke/utils/log-collector.js +226 -0
  34. package/dist/kosuke/utils/log-collector.js.map +1 -0
  35. package/dist/kosuke/utils/playwright-agent.d.ts +39 -0
  36. package/dist/kosuke/utils/playwright-agent.d.ts.map +1 -0
  37. package/dist/kosuke/utils/playwright-agent.js +245 -0
  38. package/dist/kosuke/utils/playwright-agent.js.map +1 -0
  39. package/dist/kosuke/utils/test-generator.d.ts +22 -0
  40. package/dist/kosuke/utils/test-generator.d.ts.map +1 -0
  41. package/dist/kosuke/utils/test-generator.js +174 -0
  42. package/dist/kosuke/utils/test-generator.js.map +1 -0
  43. package/dist/kosuke/utils/validator.d.ts +11 -0
  44. package/dist/kosuke/utils/validator.d.ts.map +1 -1
  45. package/dist/kosuke/utils/validator.js +100 -0
  46. package/dist/kosuke/utils/validator.js.map +1 -1
  47. package/dist/kosuke/utils/visual-tester.d.ts +71 -0
  48. package/dist/kosuke/utils/visual-tester.d.ts.map +1 -0
  49. package/dist/kosuke/utils/visual-tester.js +202 -0
  50. package/dist/kosuke/utils/visual-tester.js.map +1 -0
  51. package/dist/lib.d.ts +6 -2
  52. package/dist/lib.d.ts.map +1 -1
  53. package/dist/lib.js +5 -1
  54. package/dist/lib.js.map +1 -1
  55. package/package.json +6 -1
@@ -101,4 +101,43 @@ export async function getCurrentBranch() {
101
101
  const branch = await git.revparse(['--abbrev-ref', 'HEAD']);
102
102
  return branch.trim();
103
103
  }
104
+ /**
105
+ * Commit and push to current branch (no branch creation, no PR)
106
+ */
107
+ export async function commitAndPushCurrentBranch(message) {
108
+ await ensureGitIdentity();
109
+ // Check if there are changes to commit
110
+ const status = await git.status();
111
+ if (status.files.length === 0) {
112
+ console.log('ℹ️ No changes to commit');
113
+ return;
114
+ }
115
+ // Commit changes
116
+ await git.add(['-A']);
117
+ await git.commit(message, ['--no-verify']);
118
+ // Push to current branch
119
+ const currentBranch = await getCurrentBranch();
120
+ await git.push('origin', currentBranch);
121
+ }
122
+ /**
123
+ * Get git diff of current changes (staged and unstaged)
124
+ */
125
+ export async function getGitDiff() {
126
+ try {
127
+ // Get diff of both staged and unstaged changes
128
+ const diff = await git.diff(['HEAD']);
129
+ return diff;
130
+ }
131
+ catch (error) {
132
+ console.warn('⚠️ Could not get git diff:', error);
133
+ return '';
134
+ }
135
+ }
136
+ /**
137
+ * Check if there are any uncommitted changes
138
+ */
139
+ export async function hasUncommittedChanges() {
140
+ const status = await git.status();
141
+ return status.files.length > 0;
142
+ }
104
143
  //# sourceMappingURL=git.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"git.js","sourceRoot":"","sources":["../../../kosuke/utils/git.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../../kosuke/utils/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Log Collector - Collect logs from multiple sources
3
+ *
4
+ * Collects and aggregates logs from:
5
+ * - Browser console (errors, warnings)
6
+ * - Network requests (failed requests, status codes)
7
+ * - Docker Compose logs (backend logs)
8
+ * - Playwright traces
9
+ */
10
+ import type { Page } from '@playwright/test';
11
+ export interface ConsoleLog {
12
+ type: 'error' | 'warning' | 'info';
13
+ message: string;
14
+ timestamp: Date;
15
+ location?: string;
16
+ }
17
+ export interface NetworkLog {
18
+ url: string;
19
+ method: string;
20
+ status: number;
21
+ statusText: string;
22
+ timestamp: Date;
23
+ responseBody?: string;
24
+ requestBody?: string;
25
+ }
26
+ export interface DockerLog {
27
+ service: string;
28
+ message: string;
29
+ timestamp: Date;
30
+ }
31
+ export interface CollectedLogs {
32
+ console: ConsoleLog[];
33
+ network: NetworkLog[];
34
+ docker: DockerLog[];
35
+ }
36
+ /**
37
+ * Log collector class that attaches to a Playwright page
38
+ */
39
+ export declare class LogCollector {
40
+ private consoleLogs;
41
+ private networkLogs;
42
+ private dockerLogs;
43
+ private page;
44
+ /**
45
+ * Attach log collectors to a Playwright page
46
+ */
47
+ attach(page: Page): void;
48
+ /**
49
+ * Attach console listener
50
+ */
51
+ private attachConsoleListener;
52
+ /**
53
+ * Attach network listener
54
+ */
55
+ private attachNetworkListener;
56
+ /**
57
+ * Collect Docker Compose logs
58
+ */
59
+ collectDockerLogs(since?: string): Promise<void>;
60
+ /**
61
+ * Get all collected logs
62
+ */
63
+ getLogs(): CollectedLogs;
64
+ /**
65
+ * Get only error logs
66
+ */
67
+ getErrors(): CollectedLogs;
68
+ /**
69
+ * Check if there are any errors
70
+ */
71
+ hasErrors(): boolean;
72
+ /**
73
+ * Format logs as human-readable text
74
+ */
75
+ formatLogs(logs: CollectedLogs): string;
76
+ /**
77
+ * Clear all collected logs
78
+ */
79
+ clear(): void;
80
+ }
81
+ //# sourceMappingURL=log-collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-collector.d.ts","sourceRoot":"","sources":["../../../kosuke/utils/log-collector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,kBAAkB,CAAC;AAEvD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,IAAI,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,IAAI,CAAqB;IAEjC;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAMxB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAwB7B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAoD7B;;OAEG;IACG,iBAAiB,CAAC,KAAK,GAAE,MAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA6C7D;;OAEG;IACH,OAAO,IAAI,aAAa;IAQxB;;OAEG;IACH,SAAS,IAAI,aAAa;IAa1B;;OAEG;IACH,SAAS,IAAI,OAAO;IAKpB;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM;IAqCvC;;OAEG;IACH,KAAK,IAAI,IAAI;CAKd"}
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Log Collector - Collect logs from multiple sources
3
+ *
4
+ * Collects and aggregates logs from:
5
+ * - Browser console (errors, warnings)
6
+ * - Network requests (failed requests, status codes)
7
+ * - Docker Compose logs (backend logs)
8
+ * - Playwright traces
9
+ */
10
+ import { execSync } from 'child_process';
11
+ /**
12
+ * Log collector class that attaches to a Playwright page
13
+ */
14
+ export class LogCollector {
15
+ constructor() {
16
+ this.consoleLogs = [];
17
+ this.networkLogs = [];
18
+ this.dockerLogs = [];
19
+ this.page = null;
20
+ }
21
+ /**
22
+ * Attach log collectors to a Playwright page
23
+ */
24
+ attach(page) {
25
+ this.page = page;
26
+ this.attachConsoleListener(page);
27
+ this.attachNetworkListener(page);
28
+ }
29
+ /**
30
+ * Attach console listener
31
+ */
32
+ attachConsoleListener(page) {
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
+ page.on('console', (msg) => {
35
+ const type = msg.type();
36
+ if (type === 'error' || type === 'warning' || type === 'info') {
37
+ this.consoleLogs.push({
38
+ type: type,
39
+ message: msg.text(),
40
+ timestamp: new Date(),
41
+ location: msg.location()?.url,
42
+ });
43
+ }
44
+ });
45
+ // Also capture page errors
46
+ page.on('pageerror', (error) => {
47
+ this.consoleLogs.push({
48
+ type: 'error',
49
+ message: error.message,
50
+ timestamp: new Date(),
51
+ });
52
+ });
53
+ }
54
+ /**
55
+ * Attach network listener
56
+ */
57
+ attachNetworkListener(page) {
58
+ page.on('response', async (response) => {
59
+ const status = response.status();
60
+ // Only log failed requests or important status codes
61
+ if (status >= 400 || status === 0) {
62
+ let responseBody;
63
+ let requestBody;
64
+ try {
65
+ // Try to get response body (might fail for non-text responses)
66
+ responseBody = await response.text();
67
+ }
68
+ catch {
69
+ // Ignore if we can't get the body
70
+ }
71
+ try {
72
+ // Try to get request body
73
+ const request = response.request();
74
+ const postData = request.postData();
75
+ if (postData) {
76
+ requestBody = postData;
77
+ }
78
+ }
79
+ catch {
80
+ // Ignore if we can't get request data
81
+ }
82
+ this.networkLogs.push({
83
+ url: response.url(),
84
+ method: response.request().method(),
85
+ status,
86
+ statusText: response.statusText(),
87
+ timestamp: new Date(),
88
+ responseBody,
89
+ requestBody,
90
+ });
91
+ }
92
+ });
93
+ // Capture request failures
94
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
95
+ page.on('requestfailed', (request) => {
96
+ this.networkLogs.push({
97
+ url: request.url(),
98
+ method: request.method(),
99
+ status: 0,
100
+ statusText: request.failure()?.errorText || 'Request failed',
101
+ timestamp: new Date(),
102
+ });
103
+ });
104
+ }
105
+ /**
106
+ * Collect Docker Compose logs
107
+ */
108
+ async collectDockerLogs(since = '30s') {
109
+ try {
110
+ // Check if docker compose is available
111
+ try {
112
+ execSync('docker compose version', { stdio: 'ignore' });
113
+ }
114
+ catch {
115
+ console.log(' ℹ️ Docker Compose not available, skipping backend logs');
116
+ return;
117
+ }
118
+ // Get logs from all services
119
+ const logs = execSync(`docker compose logs --tail=100 --since=${since} --no-color`, {
120
+ encoding: 'utf-8',
121
+ stdio: ['pipe', 'pipe', 'ignore'], // Ignore stderr
122
+ });
123
+ // Parse logs
124
+ const lines = logs.split('\n');
125
+ for (const line of lines) {
126
+ if (!line.trim())
127
+ continue;
128
+ // Docker compose log format: service-name | message
129
+ const match = line.match(/^([a-zA-Z0-9_-]+)\s+\|\s+(.+)$/);
130
+ if (match) {
131
+ const [, service, message] = match;
132
+ this.dockerLogs.push({
133
+ service: service.trim(),
134
+ message: message.trim(),
135
+ timestamp: new Date(),
136
+ });
137
+ }
138
+ else {
139
+ // Fallback: just store the line as-is
140
+ this.dockerLogs.push({
141
+ service: 'unknown',
142
+ message: line,
143
+ timestamp: new Date(),
144
+ });
145
+ }
146
+ }
147
+ }
148
+ catch (error) {
149
+ console.log(' ⚠️ Failed to collect Docker logs:', error);
150
+ // Don't throw - backend logs are optional
151
+ }
152
+ }
153
+ /**
154
+ * Get all collected logs
155
+ */
156
+ getLogs() {
157
+ return {
158
+ console: this.consoleLogs,
159
+ network: this.networkLogs,
160
+ docker: this.dockerLogs,
161
+ };
162
+ }
163
+ /**
164
+ * Get only error logs
165
+ */
166
+ getErrors() {
167
+ return {
168
+ console: this.consoleLogs.filter((log) => log.type === 'error'),
169
+ network: this.networkLogs.filter((log) => log.status >= 400 || log.status === 0),
170
+ docker: this.dockerLogs.filter((log) => log.message.toLowerCase().includes('error') ||
171
+ log.message.toLowerCase().includes('exception') ||
172
+ log.message.toLowerCase().includes('failed')),
173
+ };
174
+ }
175
+ /**
176
+ * Check if there are any errors
177
+ */
178
+ hasErrors() {
179
+ const errors = this.getErrors();
180
+ return errors.console.length > 0 || errors.network.length > 0 || errors.docker.length > 0;
181
+ }
182
+ /**
183
+ * Format logs as human-readable text
184
+ */
185
+ formatLogs(logs) {
186
+ const sections = [];
187
+ // Console logs
188
+ if (logs.console.length > 0) {
189
+ sections.push('=== Console Logs ===');
190
+ for (const log of logs.console) {
191
+ const location = log.location ? ` (${log.location})` : '';
192
+ sections.push(`[${log.type.toUpperCase()}]${location} ${log.message}`);
193
+ }
194
+ }
195
+ // Network logs
196
+ if (logs.network.length > 0) {
197
+ sections.push('\n=== Network Logs ===');
198
+ for (const log of logs.network) {
199
+ sections.push(`[${log.method}] ${log.url} - ${log.status} ${log.statusText}`);
200
+ if (log.requestBody) {
201
+ sections.push(` Request: ${log.requestBody.substring(0, 200)}`);
202
+ }
203
+ if (log.responseBody) {
204
+ sections.push(` Response: ${log.responseBody.substring(0, 200)}`);
205
+ }
206
+ }
207
+ }
208
+ // Docker logs
209
+ if (logs.docker.length > 0) {
210
+ sections.push('\n=== Docker Compose Logs ===');
211
+ for (const log of logs.docker) {
212
+ sections.push(`[${log.service}] ${log.message}`);
213
+ }
214
+ }
215
+ return sections.join('\n');
216
+ }
217
+ /**
218
+ * Clear all collected logs
219
+ */
220
+ clear() {
221
+ this.consoleLogs = [];
222
+ this.networkLogs = [];
223
+ this.dockerLogs = [];
224
+ }
225
+ }
226
+ //# sourceMappingURL=log-collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-collector.js","sourceRoot":"","sources":["../../../kosuke/utils/log-collector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Playwright Agent - Test execution orchestration
3
+ *
4
+ * Executes Playwright tests with logging and visual regression
5
+ */
6
+ import type { TestFailure } from './error-analyzer.js';
7
+ export interface PlaywrightResult {
8
+ success: boolean;
9
+ testsRun: number;
10
+ testsPassed: number;
11
+ testsFailed: number;
12
+ failures: TestFailure[];
13
+ tracePath: string;
14
+ duration: number;
15
+ }
16
+ export interface PlaywrightOptions {
17
+ testFile: string;
18
+ baseUrl: string;
19
+ headed?: boolean;
20
+ debug?: boolean;
21
+ cwd?: string;
22
+ }
23
+ /**
24
+ * Run Playwright tests
25
+ */
26
+ export declare function runPlaywrightTests(options: PlaywrightOptions): Promise<PlaywrightResult>;
27
+ /**
28
+ * Check if Playwright is installed
29
+ */
30
+ export declare function isPlaywrightInstalled(cwd?: string): boolean;
31
+ /**
32
+ * Install Playwright
33
+ */
34
+ export declare function installPlaywright(cwd?: string): Promise<void>;
35
+ /**
36
+ * Ensure Playwright config exists
37
+ */
38
+ export declare function ensurePlaywrightConfig(cwd?: string): void;
39
+ //# sourceMappingURL=playwright-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playwright-agent.d.ts","sourceRoot":"","sources":["../../../kosuke/utils/playwright-agent.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA6D9F;AA4HD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAW1E;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBlF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,GAAE,MAAsB,GAAG,IAAI,CAmCxE"}
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Playwright Agent - Test execution orchestration
3
+ *
4
+ * Executes Playwright tests with logging and visual regression
5
+ */
6
+ import { execSync } from 'child_process';
7
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
8
+ import { join } from 'path';
9
+ /**
10
+ * Run Playwright tests
11
+ */
12
+ export async function runPlaywrightTests(options) {
13
+ const { testFile, baseUrl, headed = false, debug = false, cwd = process.cwd() } = options;
14
+ // Ensure test results directory exists
15
+ const resultsDir = join(cwd, 'test-results');
16
+ if (!existsSync(resultsDir)) {
17
+ mkdirSync(resultsDir, { recursive: true });
18
+ }
19
+ const ticketId = testFile.split('/').pop()?.replace('.spec.ts', '') || 'unknown';
20
+ const tracePath = join(resultsDir, `trace-${ticketId}.zip`);
21
+ // Build Playwright command
22
+ const args = [
23
+ 'playwright',
24
+ 'test',
25
+ testFile,
26
+ `--config=${join(cwd, 'playwright.config.ts')}`,
27
+ '--reporter=json',
28
+ ];
29
+ if (headed) {
30
+ args.push('--headed');
31
+ }
32
+ if (debug) {
33
+ args.push('--debug');
34
+ }
35
+ // Set environment variables
36
+ const env = {
37
+ ...process.env,
38
+ BASE_URL: baseUrl,
39
+ PLAYWRIGHT_TRACE: 'on',
40
+ };
41
+ console.log(` 🎯 Running Playwright tests...`);
42
+ const startTime = Date.now();
43
+ try {
44
+ // Run Playwright using npx (works with any package manager)
45
+ const output = execSync(`npx ${args.join(' ')}`, {
46
+ cwd,
47
+ env,
48
+ encoding: 'utf-8',
49
+ stdio: ['pipe', 'pipe', 'pipe'], // Capture all output
50
+ });
51
+ const duration = Date.now() - startTime;
52
+ const result = parsePlaywrightOutput(output, tracePath, duration);
53
+ return result;
54
+ }
55
+ catch (error) {
56
+ // Playwright exits with non-zero code when tests fail
57
+ const duration = Date.now() - startTime;
58
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
59
+ const output = error instanceof Error && 'stdout' in error ? error.stdout : '';
60
+ const result = parsePlaywrightOutput(output, tracePath, duration);
61
+ return result;
62
+ }
63
+ }
64
+ /**
65
+ * Parse Playwright JSON output
66
+ */
67
+ function parsePlaywrightOutput(output, tracePath, duration) {
68
+ try {
69
+ // Try to parse JSON output
70
+ const jsonMatch = output.match(/\{[\s\S]*"suites"[\s\S]*\}/);
71
+ if (jsonMatch) {
72
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
73
+ const json = JSON.parse(jsonMatch[0]);
74
+ return parsePlaywrightJson(json, tracePath, duration);
75
+ }
76
+ }
77
+ catch {
78
+ // If JSON parsing fails, fall back to text parsing
79
+ }
80
+ // Fallback: parse text output
81
+ return parsePlaywrightText(output, tracePath, duration);
82
+ }
83
+ /**
84
+ * Parse Playwright JSON report
85
+ */
86
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
87
+ function parsePlaywrightJson(json, tracePath, duration) {
88
+ const failures = [];
89
+ let testsRun = 0;
90
+ let testsPassed = 0;
91
+ let testsFailed = 0;
92
+ // Parse test results
93
+ for (const suite of json.suites || []) {
94
+ for (const spec of suite.specs || []) {
95
+ for (const test of spec.tests || []) {
96
+ testsRun++;
97
+ const result = test.results?.[0];
98
+ if (result?.status === 'passed') {
99
+ testsPassed++;
100
+ }
101
+ else {
102
+ testsFailed++;
103
+ failures.push({
104
+ testName: spec.title || 'Unknown test',
105
+ errorMessage: result?.error?.message || 'Test failed',
106
+ expected: extractExpected(result?.error?.message),
107
+ received: extractReceived(result?.error?.message),
108
+ });
109
+ }
110
+ }
111
+ }
112
+ }
113
+ return {
114
+ success: testsFailed === 0,
115
+ testsRun,
116
+ testsPassed,
117
+ testsFailed,
118
+ failures,
119
+ tracePath,
120
+ duration,
121
+ };
122
+ }
123
+ /**
124
+ * Parse Playwright text output (fallback)
125
+ */
126
+ function parsePlaywrightText(output, tracePath, duration) {
127
+ const failures = [];
128
+ // Look for test failures in output
129
+ const failureMatches = output.matchAll(/✘ (.+?)\n[\s\S]*?Error: (.+?)(?:\n|$)/g);
130
+ for (const match of failureMatches) {
131
+ failures.push({
132
+ testName: match[1].trim(),
133
+ errorMessage: match[2].trim(),
134
+ });
135
+ }
136
+ // Count tests
137
+ const passedMatch = output.match(/(\d+) passed/);
138
+ const failedMatch = output.match(/(\d+) failed/);
139
+ const testsPassed = passedMatch ? parseInt(passedMatch[1]) : 0;
140
+ const testsFailed = failedMatch ? parseInt(failedMatch[1]) : failures.length;
141
+ const testsRun = testsPassed + testsFailed;
142
+ return {
143
+ success: testsFailed === 0,
144
+ testsRun,
145
+ testsPassed,
146
+ testsFailed,
147
+ failures,
148
+ tracePath,
149
+ duration,
150
+ };
151
+ }
152
+ /**
153
+ * Extract expected value from error message
154
+ */
155
+ function extractExpected(errorMessage) {
156
+ if (!errorMessage)
157
+ return undefined;
158
+ const match = errorMessage.match(/Expected:?\s*(.+?)(?:\n|Received)/i);
159
+ return match ? match[1].trim() : undefined;
160
+ }
161
+ /**
162
+ * Extract received value from error message
163
+ */
164
+ function extractReceived(errorMessage) {
165
+ if (!errorMessage)
166
+ return undefined;
167
+ const match = errorMessage.match(/Received:?\s*(.+?)(?:\n|$)/i);
168
+ return match ? match[1].trim() : undefined;
169
+ }
170
+ /**
171
+ * Check if Playwright is installed
172
+ */
173
+ export function isPlaywrightInstalled(cwd = process.cwd()) {
174
+ try {
175
+ execSync('npx playwright --version', {
176
+ cwd,
177
+ encoding: 'utf-8',
178
+ stdio: 'ignore',
179
+ });
180
+ return true;
181
+ }
182
+ catch {
183
+ return false;
184
+ }
185
+ }
186
+ /**
187
+ * Install Playwright
188
+ */
189
+ export async function installPlaywright(cwd = process.cwd()) {
190
+ console.log('📦 Installing Playwright...');
191
+ try {
192
+ // Install @playwright/test
193
+ execSync('npm install --save-dev @playwright/test', {
194
+ cwd,
195
+ encoding: 'utf-8',
196
+ stdio: 'inherit',
197
+ });
198
+ // Install browsers
199
+ execSync('npx playwright install chromium', {
200
+ cwd,
201
+ encoding: 'utf-8',
202
+ stdio: 'inherit',
203
+ });
204
+ console.log(' ✅ Playwright installed\n');
205
+ }
206
+ catch (error) {
207
+ throw new Error(`Failed to install Playwright: ${error}`);
208
+ }
209
+ }
210
+ /**
211
+ * Ensure Playwright config exists
212
+ */
213
+ export function ensurePlaywrightConfig(cwd = process.cwd()) {
214
+ const configPath = join(cwd, 'playwright.config.ts');
215
+ if (existsSync(configPath)) {
216
+ return; // Config already exists
217
+ }
218
+ console.log('📝 Creating playwright.config.ts...');
219
+ const configContent = `import { defineConfig, devices } from '@playwright/test';
220
+
221
+ export default defineConfig({
222
+ testDir: './.kosuke/tests',
223
+ fullyParallel: false,
224
+ forbidOnly: !!process.env.CI,
225
+ retries: 0,
226
+ workers: 1,
227
+ reporter: 'html',
228
+ use: {
229
+ baseURL: process.env.BASE_URL || 'http://localhost:3000',
230
+ trace: 'retain-on-failure',
231
+ screenshot: 'only-on-failure',
232
+ video: 'retain-on-failure',
233
+ },
234
+ projects: [
235
+ {
236
+ name: 'chromium',
237
+ use: { ...devices['Desktop Chrome'] },
238
+ },
239
+ ],
240
+ });
241
+ `;
242
+ writeFileSync(configPath, configContent, 'utf-8');
243
+ console.log(' ✅ Config created\n');
244
+ }
245
+ //# sourceMappingURL=playwright-agent.js.map