@kosuke-ai/cli 0.0.13 → 0.0.15

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 (43) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +61 -2
  4. package/dist/index.js.map +1 -1
  5. package/dist/kosuke/commands/build.d.ts +1 -0
  6. package/dist/kosuke/commands/build.d.ts.map +1 -1
  7. package/dist/kosuke/commands/build.js +5 -1
  8. package/dist/kosuke/commands/build.js.map +1 -1
  9. package/dist/kosuke/commands/ship.d.ts +1 -0
  10. package/dist/kosuke/commands/ship.d.ts.map +1 -1
  11. package/dist/kosuke/commands/ship.js +26 -2
  12. package/dist/kosuke/commands/ship.js.map +1 -1
  13. package/dist/kosuke/commands/test.d.ts +27 -0
  14. package/dist/kosuke/commands/test.d.ts.map +1 -0
  15. package/dist/kosuke/commands/test.js +338 -0
  16. package/dist/kosuke/commands/test.js.map +1 -0
  17. package/dist/kosuke/types.d.ts +38 -1
  18. package/dist/kosuke/types.d.ts.map +1 -1
  19. package/dist/kosuke/utils/error-analyzer.d.ts +32 -0
  20. package/dist/kosuke/utils/error-analyzer.d.ts.map +1 -0
  21. package/dist/kosuke/utils/error-analyzer.js +129 -0
  22. package/dist/kosuke/utils/error-analyzer.js.map +1 -0
  23. package/dist/kosuke/utils/log-collector.d.ts +81 -0
  24. package/dist/kosuke/utils/log-collector.d.ts.map +1 -0
  25. package/dist/kosuke/utils/log-collector.js +226 -0
  26. package/dist/kosuke/utils/log-collector.js.map +1 -0
  27. package/dist/kosuke/utils/playwright-agent.d.ts +39 -0
  28. package/dist/kosuke/utils/playwright-agent.d.ts.map +1 -0
  29. package/dist/kosuke/utils/playwright-agent.js +245 -0
  30. package/dist/kosuke/utils/playwright-agent.js.map +1 -0
  31. package/dist/kosuke/utils/test-generator.d.ts +22 -0
  32. package/dist/kosuke/utils/test-generator.d.ts.map +1 -0
  33. package/dist/kosuke/utils/test-generator.js +174 -0
  34. package/dist/kosuke/utils/test-generator.js.map +1 -0
  35. package/dist/kosuke/utils/visual-tester.d.ts +71 -0
  36. package/dist/kosuke/utils/visual-tester.d.ts.map +1 -0
  37. package/dist/kosuke/utils/visual-tester.js +202 -0
  38. package/dist/kosuke/utils/visual-tester.js.map +1 -0
  39. package/dist/lib.d.ts +2 -1
  40. package/dist/lib.d.ts.map +1 -1
  41. package/dist/lib.js +1 -0
  42. package/dist/lib.js.map +1 -1
  43. package/package.json +6 -1
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Test Generator - AI-powered Playwright test generation
3
+ *
4
+ * Uses Claude to generate Playwright tests from ticket descriptions
5
+ */
6
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
7
+ import { join } from 'path';
8
+ import { runAgent } from './claude-agent.js';
9
+ /**
10
+ * Generate Playwright test from ticket description
11
+ */
12
+ export async function generateTest(ticket, baseUrl, cwd = process.cwd()) {
13
+ const testDir = join(cwd, '.kosuke', 'tests');
14
+ const testFilePath = join(testDir, `${ticket.id}.spec.ts`);
15
+ // Ensure test directory exists
16
+ if (!existsSync(testDir)) {
17
+ mkdirSync(testDir, { recursive: true });
18
+ }
19
+ // Check if test already exists
20
+ if (existsSync(testFilePath)) {
21
+ console.log(` āœ… Test already exists: ${testFilePath}`);
22
+ return {
23
+ filePath: testFilePath,
24
+ content: '',
25
+ tokensUsed: {
26
+ input: 0,
27
+ output: 0,
28
+ cacheCreation: 0,
29
+ cacheRead: 0,
30
+ },
31
+ cost: 0,
32
+ };
33
+ }
34
+ console.log(` šŸ¤– Generating test using Claude...`);
35
+ const systemPrompt = buildTestGenerationPrompt(ticket, baseUrl);
36
+ const result = await runAgent(`Generate Playwright test for ticket ${ticket.id}`, {
37
+ systemPrompt,
38
+ cwd,
39
+ maxTurns: 15,
40
+ verbosity: 'minimal',
41
+ });
42
+ // Extract test code from response
43
+ const testContent = extractTestCode(result.response, ticket, baseUrl);
44
+ // Save test file
45
+ writeFileSync(testFilePath, testContent, 'utf-8');
46
+ console.log(` āœ… Test generated: ${testFilePath}`);
47
+ return {
48
+ filePath: testFilePath,
49
+ content: testContent,
50
+ tokensUsed: result.tokensUsed,
51
+ cost: result.cost,
52
+ };
53
+ }
54
+ /**
55
+ * Build system prompt for test generation
56
+ */
57
+ function buildTestGenerationPrompt(ticket, baseUrl) {
58
+ return `You are an expert QA engineer creating Playwright end-to-end tests.
59
+
60
+ **Your Task:**
61
+ Generate a comprehensive Playwright test file for the following ticket.
62
+
63
+ **Ticket Information:**
64
+ - ID: ${ticket.id}
65
+ - Title: ${ticket.title}
66
+ - Description:
67
+ ${ticket.description}
68
+
69
+ **Application URL:** ${baseUrl}
70
+
71
+ **Test Requirements:**
72
+ 1. Create a complete Playwright test file in TypeScript
73
+ 2. Include multiple test cases covering:
74
+ - Happy path (main functionality)
75
+ - Edge cases (validation, errors)
76
+ - Visual regression test (one screenshot)
77
+ 3. Use proper Playwright selectors (prefer getByRole, getByLabel, getByText)
78
+ 4. Include proper assertions with expect()
79
+ 5. Add comments explaining what each test does
80
+ 6. Follow Playwright best practices
81
+
82
+ **Test Structure:**
83
+ \`\`\`typescript
84
+ import { test, expect } from '@playwright/test';
85
+
86
+ test.describe('${ticket.id}: ${ticket.title}', () => {
87
+ test.beforeEach(async ({ page }) => {
88
+ // Navigate to the relevant page
89
+ await page.goto('${baseUrl}/...');
90
+ });
91
+
92
+ test('should [describe main functionality]', async ({ page }) => {
93
+ // Test implementation
94
+ });
95
+
96
+ test('should handle [edge case]', async ({ page }) => {
97
+ // Test implementation
98
+ });
99
+
100
+ test('visual regression: [page/component] renders correctly', async ({ page }) => {
101
+ // Wait for page to be stable
102
+ await page.waitForLoadState('networkidle');
103
+
104
+ // Take screenshot
105
+ const screenshot = await page.screenshot({ fullPage: true });
106
+
107
+ // Compare with baseline (handled by visual tester)
108
+ expect(screenshot).toBeDefined();
109
+ });
110
+ });
111
+ \`\`\`
112
+
113
+ **Critical Instructions:**
114
+ 1. Analyze the ticket description to understand what features to test
115
+ 2. Determine the correct URL paths based on the feature
116
+ 3. Generate realistic test data (emails, names, etc.)
117
+ 4. Include proper waits (waitForLoadState, waitForSelector)
118
+ 5. Test both success and failure scenarios
119
+ 6. Add one visual regression test at the end
120
+ 7. Output ONLY the test code - no explanations outside the code
121
+
122
+ Generate the complete test file now:`;
123
+ }
124
+ /**
125
+ * Extract test code from Claude's response
126
+ */
127
+ function extractTestCode(response, ticket, baseUrl) {
128
+ // Look for code blocks in the response
129
+ const codeBlockMatch = response.match(/```(?:typescript|ts)?\n([\s\S]+?)\n```/);
130
+ if (codeBlockMatch) {
131
+ return codeBlockMatch[1].trim();
132
+ }
133
+ // If no code block found, try to use the whole response
134
+ // or generate a basic template
135
+ if (response.includes('import') && response.includes('test(')) {
136
+ return response.trim();
137
+ }
138
+ // Fallback: generate basic template
139
+ console.log(' āš ļø Could not extract test code, generating basic template');
140
+ return generateBasicTemplate(ticket, baseUrl);
141
+ }
142
+ /**
143
+ * Generate a basic test template as fallback
144
+ */
145
+ function generateBasicTemplate(ticket, baseUrl) {
146
+ return `import { test, expect } from '@playwright/test';
147
+
148
+ test.describe('${ticket.id}: ${ticket.title}', () => {
149
+ test.beforeEach(async ({ page }) => {
150
+ // TODO: Update this URL to the correct path for the feature
151
+ await page.goto('${baseUrl}');
152
+ });
153
+
154
+ test('should load the page', async ({ page }) => {
155
+ // TODO: Add assertions to verify the page loaded correctly
156
+ await expect(page.locator('body')).toBeVisible();
157
+ });
158
+
159
+ test('should interact with main feature', async ({ page }) => {
160
+ // TODO: Add test steps for the main functionality
161
+ // Example:
162
+ // await page.getByRole('button', { name: 'Submit' }).click();
163
+ // await expect(page.getByText('Success')).toBeVisible();
164
+ });
165
+
166
+ test('visual regression: page renders correctly', async ({ page }) => {
167
+ await page.waitForLoadState('networkidle');
168
+ const screenshot = await page.screenshot({ fullPage: true });
169
+ expect(screenshot).toBeDefined();
170
+ });
171
+ });
172
+ `;
173
+ }
174
+ //# sourceMappingURL=test-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-generator.js","sourceRoot":"","sources":["../../../kosuke/utils/test-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Visual Tester - Visual regression testing with screenshot comparison
3
+ *
4
+ * Inspired by Subito.it's approach:
5
+ * - Capture screenshots of pages
6
+ * - Compare against baseline images
7
+ * - Detect pixel differences above threshold
8
+ * - Hide dynamic content (ads, analytics)
9
+ */
10
+ import type { Page } from '@playwright/test';
11
+ export interface VisualDiff {
12
+ testName: string;
13
+ diffPixels: number;
14
+ diffPercentage: number;
15
+ threshold: number;
16
+ passed: boolean;
17
+ baselinePath: string;
18
+ currentPath: string;
19
+ diffPath: string;
20
+ }
21
+ export interface VisualTestOptions {
22
+ ticketId: string;
23
+ testName: string;
24
+ threshold?: number;
25
+ updateBaseline?: boolean;
26
+ }
27
+ /**
28
+ * Visual Tester class for screenshot comparison
29
+ */
30
+ export declare class VisualTester {
31
+ private cwd;
32
+ private diffs;
33
+ constructor(cwd?: string);
34
+ /**
35
+ * Hide dynamic content that shouldn't be tested
36
+ */
37
+ hideDynamicContent(page: Page): Promise<void>;
38
+ /**
39
+ * Take a screenshot and compare with baseline
40
+ */
41
+ captureAndCompare(page: Page, options: VisualTestOptions): Promise<VisualDiff>;
42
+ /**
43
+ * Compare two images and generate diff
44
+ */
45
+ private compareImages;
46
+ /**
47
+ * Get all visual diffs
48
+ */
49
+ getDiffs(): VisualDiff[];
50
+ /**
51
+ * Get failed visual diffs
52
+ */
53
+ getFailedDiffs(): VisualDiff[];
54
+ /**
55
+ * Check if there are any visual regressions
56
+ */
57
+ hasRegressions(): boolean;
58
+ /**
59
+ * Format visual diff report
60
+ */
61
+ formatReport(): string;
62
+ /**
63
+ * Clear all diffs
64
+ */
65
+ clear(): void;
66
+ /**
67
+ * Ensure directory exists
68
+ */
69
+ private ensureDir;
70
+ }
71
+ //# sourceMappingURL=visual-tester.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-tester.d.ts","sourceRoot":"","sources":["../../../kosuke/utils/visual-tester.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAI7C,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,KAAK,CAAoB;gBAErB,GAAG,GAAE,MAAsB;IAIvC;;OAEG;IACG,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBnD;;OAEG;IACG,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC;IAuDpF;;OAEG;IACH,OAAO,CAAC,aAAa;IAwErB;;OAEG;IACH,QAAQ,IAAI,UAAU,EAAE;IAIxB;;OAEG;IACH,cAAc,IAAI,UAAU,EAAE;IAI9B;;OAEG;IACH,cAAc,IAAI,OAAO;IAIzB;;OAEG;IACH,YAAY,IAAI,MAAM;IA2BtB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,OAAO,CAAC,SAAS;CAKlB"}
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Visual Tester - Visual regression testing with screenshot comparison
3
+ *
4
+ * Inspired by Subito.it's approach:
5
+ * - Capture screenshots of pages
6
+ * - Compare against baseline images
7
+ * - Detect pixel differences above threshold
8
+ * - Hide dynamic content (ads, analytics)
9
+ */
10
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
11
+ import { join } from 'path';
12
+ import { PNG } from 'pngjs';
13
+ import pixelmatch from 'pixelmatch';
14
+ /**
15
+ * Visual Tester class for screenshot comparison
16
+ */
17
+ export class VisualTester {
18
+ constructor(cwd = process.cwd()) {
19
+ this.diffs = [];
20
+ this.cwd = cwd;
21
+ }
22
+ /**
23
+ * Hide dynamic content that shouldn't be tested
24
+ */
25
+ async hideDynamicContent(page) {
26
+ await page.addStyleTag({
27
+ content: `
28
+ /* Hide common dynamic content */
29
+ .advertisement,
30
+ .ad-banner,
31
+ .analytics-widget,
32
+ .third-party-banner,
33
+ [class*="ad-"],
34
+ [id*="ad-"],
35
+ [class*="analytics"],
36
+ [id*="analytics"] {
37
+ display: none !important;
38
+ visibility: hidden !important;
39
+ }
40
+ `,
41
+ });
42
+ }
43
+ /**
44
+ * Take a screenshot and compare with baseline
45
+ */
46
+ async captureAndCompare(page, options) {
47
+ const { ticketId, testName, threshold = 0.01, updateBaseline = false } = options;
48
+ // Ensure visual test directories exist
49
+ const baselineDir = join(this.cwd, '.kosuke', 'visual-tests', 'baselines', ticketId);
50
+ const currentDir = join(this.cwd, '.kosuke', 'visual-tests', 'current', ticketId);
51
+ const diffDir = join(this.cwd, '.kosuke', 'visual-tests', 'diffs', ticketId);
52
+ this.ensureDir(baselineDir);
53
+ this.ensureDir(currentDir);
54
+ this.ensureDir(diffDir);
55
+ const baselinePath = join(baselineDir, `${testName}.png`);
56
+ const currentPath = join(currentDir, `${testName}.png`);
57
+ const diffPath = join(diffDir, `${testName}.png`);
58
+ // Hide dynamic content before taking screenshot
59
+ await this.hideDynamicContent(page);
60
+ // Wait for page to be stable
61
+ await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {
62
+ // Ignore timeout - some pages never reach networkidle
63
+ });
64
+ // Take screenshot
65
+ const screenshot = await page.screenshot({ fullPage: true });
66
+ writeFileSync(currentPath, screenshot);
67
+ // If no baseline exists or updateBaseline flag is set, create/update baseline
68
+ if (!existsSync(baselinePath) || updateBaseline) {
69
+ writeFileSync(baselinePath, screenshot);
70
+ console.log(` šŸ“ø ${updateBaseline ? 'Updated' : 'Created'} baseline: ${testName}`);
71
+ const diff = {
72
+ testName,
73
+ diffPixels: 0,
74
+ diffPercentage: 0,
75
+ threshold,
76
+ passed: true,
77
+ baselinePath,
78
+ currentPath,
79
+ diffPath,
80
+ };
81
+ this.diffs.push(diff);
82
+ return diff;
83
+ }
84
+ // Compare with baseline
85
+ const result = this.compareImages(baselinePath, currentPath, diffPath, threshold);
86
+ this.diffs.push(result);
87
+ return result;
88
+ }
89
+ /**
90
+ * Compare two images and generate diff
91
+ */
92
+ compareImages(baselinePath, currentPath, diffPath, threshold) {
93
+ const testName = baselinePath.split('/').pop()?.replace('.png', '') || 'unknown';
94
+ try {
95
+ const baseline = PNG.sync.read(readFileSync(baselinePath));
96
+ const current = PNG.sync.read(readFileSync(currentPath));
97
+ // Check if dimensions match
98
+ if (baseline.width !== current.width || baseline.height !== current.height) {
99
+ return {
100
+ testName,
101
+ diffPixels: baseline.width * baseline.height, // All pixels are different
102
+ diffPercentage: 1,
103
+ threshold,
104
+ passed: false,
105
+ baselinePath,
106
+ currentPath,
107
+ diffPath,
108
+ };
109
+ }
110
+ // Create diff image
111
+ const diff = new PNG({ width: baseline.width, height: baseline.height });
112
+ // Compare pixels
113
+ const diffPixels = pixelmatch(baseline.data, current.data, diff.data, baseline.width, baseline.height, { threshold: 0.1 } // Pixel sensitivity
114
+ );
115
+ const totalPixels = baseline.width * baseline.height;
116
+ const diffPercentage = diffPixels / totalPixels;
117
+ // Save diff image if there are differences
118
+ if (diffPixels > 0) {
119
+ writeFileSync(diffPath, PNG.sync.write(diff));
120
+ }
121
+ return {
122
+ testName,
123
+ diffPixels,
124
+ diffPercentage,
125
+ threshold,
126
+ passed: diffPercentage <= threshold,
127
+ baselinePath,
128
+ currentPath,
129
+ diffPath,
130
+ };
131
+ }
132
+ catch (error) {
133
+ console.error(` āš ļø Failed to compare images: ${error}`);
134
+ return {
135
+ testName,
136
+ diffPixels: 0,
137
+ diffPercentage: 0,
138
+ threshold,
139
+ passed: false,
140
+ baselinePath,
141
+ currentPath,
142
+ diffPath,
143
+ };
144
+ }
145
+ }
146
+ /**
147
+ * Get all visual diffs
148
+ */
149
+ getDiffs() {
150
+ return this.diffs;
151
+ }
152
+ /**
153
+ * Get failed visual diffs
154
+ */
155
+ getFailedDiffs() {
156
+ return this.diffs.filter((diff) => !diff.passed);
157
+ }
158
+ /**
159
+ * Check if there are any visual regressions
160
+ */
161
+ hasRegressions() {
162
+ return this.getFailedDiffs().length > 0;
163
+ }
164
+ /**
165
+ * Format visual diff report
166
+ */
167
+ formatReport() {
168
+ if (this.diffs.length === 0) {
169
+ return 'No visual tests run';
170
+ }
171
+ const failed = this.getFailedDiffs();
172
+ const passed = this.diffs.filter((diff) => diff.passed);
173
+ const lines = [];
174
+ lines.push(`\nšŸ“ø Visual Regression Report:`);
175
+ lines.push(` āœ… Passed: ${passed.length}`);
176
+ lines.push(` āŒ Failed: ${failed.length}`);
177
+ if (failed.length > 0) {
178
+ lines.push('\n Failed tests:');
179
+ for (const diff of failed) {
180
+ const percentage = (diff.diffPercentage * 100).toFixed(2);
181
+ lines.push(` - ${diff.testName}: ${percentage}% difference (threshold: ${diff.threshold * 100}%)`);
182
+ lines.push(` Diff image: ${diff.diffPath}`);
183
+ }
184
+ }
185
+ return lines.join('\n');
186
+ }
187
+ /**
188
+ * Clear all diffs
189
+ */
190
+ clear() {
191
+ this.diffs = [];
192
+ }
193
+ /**
194
+ * Ensure directory exists
195
+ */
196
+ ensureDir(dir) {
197
+ if (!existsSync(dir)) {
198
+ mkdirSync(dir, { recursive: true });
199
+ }
200
+ }
201
+ }
202
+ //# sourceMappingURL=visual-tester.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-tester.js","sourceRoot":"","sources":["../../../kosuke/utils/visual-tester.ts"],"names":[],"mappings":"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"}
package/dist/lib.d.ts CHANGED
@@ -39,12 +39,13 @@ export { ticketsCore } from './kosuke/commands/tickets.js';
39
39
  export { shipCommand, shipCore } from './kosuke/commands/ship.js';
40
40
  export { buildCommand } from './kosuke/commands/build.js';
41
41
  export { reviewCommand, reviewCore } from './kosuke/commands/review.js';
42
+ export { testCommand, testCore } from './kosuke/commands/test.js';
42
43
  export { discoverFiles } from './kosuke/utils/file-discovery.js';
43
44
  export { createBatches } from './kosuke/utils/batch-creator.js';
44
45
  export { runLint, runTypecheck, runFormat, runTests, runComprehensiveLinting, detectPackageManager, readPackageJsonScripts, } from './kosuke/utils/validator.js';
45
46
  export { getRepoLocalPath } from './kosuke/utils/repository-manager.js';
46
47
  export { validateRepoAccess } from './kosuke/utils/repository-resolver.js';
47
- export type { Batch, Fix, AnalyseOptions, LintOptions, SyncRulesOptions, RulesAdaptation, GitInfo, GetCodeOptions, CodeExplorationResult, TicketsOptions, TicketsResult, Ticket, ShipOptions, ShipResult, BuildOptions, ReviewOptions, ReviewResult, } from './kosuke/types.js';
48
+ export type { Batch, Fix, AnalyseOptions, LintOptions, SyncRulesOptions, RulesAdaptation, GitInfo, GetCodeOptions, CodeExplorationResult, TicketsOptions, TicketsResult, Ticket, ShipOptions, ShipResult, BuildOptions, ReviewOptions, ReviewResult, TestOptions, TestResult, AnalysisResult, TestFailure, ConsoleLog, NetworkLog, DockerLog, CollectedLogs, PlaywrightResult, PlaywrightOptions, GeneratedTest, VisualDiff, VisualTestOptions, } from './kosuke/types.js';
48
49
  export type { ValidationResult } from './kosuke/utils/validator.js';
49
50
  export type { AgentVerbosity, AgentConfig, AgentResult } from './kosuke/utils/claude-agent.js';
50
51
  //# sourceMappingURL=lib.d.ts.map
package/dist/lib.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../lib.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAGxE,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EACL,OAAO,EACP,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAG3E,YAAY,EACV,KAAK,EACL,GAAG,EACH,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,OAAO,EACP,cAAc,EACd,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,MAAM,EACN,WAAW,EACX,UAAU,EACV,YAAY,EACZ,aAAa,EACb,YAAY,GACb,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACpE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC"}
1
+ {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../lib.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAGlE,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EACL,OAAO,EACP,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAG3E,YAAY,EACV,KAAK,EACL,GAAG,EACH,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,OAAO,EACP,cAAc,EACd,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,MAAM,EACN,WAAW,EACX,UAAU,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,WAAW,EACX,UAAU,EAEV,cAAc,EACd,WAAW,EACX,UAAU,EACV,UAAU,EACV,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACpE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC"}
package/dist/lib.js CHANGED
@@ -40,6 +40,7 @@ export { ticketsCore } from './kosuke/commands/tickets.js';
40
40
  export { shipCommand, shipCore } from './kosuke/commands/ship.js';
41
41
  export { buildCommand } from './kosuke/commands/build.js';
42
42
  export { reviewCommand, reviewCore } from './kosuke/commands/review.js';
43
+ export { testCommand, testCore } from './kosuke/commands/test.js';
43
44
  // Re-export utilities
44
45
  export { discoverFiles } from './kosuke/utils/file-discovery.js';
45
46
  export { createBatches } from './kosuke/utils/batch-creator.js';
package/dist/lib.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"lib.js","sourceRoot":"","sources":["../lib.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,qBAAqB;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAExE,sBAAsB;AACtB,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EACL,OAAO,EACP,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC"}
1
+ {"version":3,"file":"lib.js","sourceRoot":"","sources":["../lib.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,qBAAqB;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAElE,sBAAsB;AACtB,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EACL,OAAO,EACP,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kosuke-ai/cli",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "Kosuke CLI - Development automation tool for syncing rules and analyzing code quality",
5
5
  "keywords": [
6
6
  "CLI",
@@ -65,7 +65,10 @@
65
65
  "simple-git": "^3.22.0"
66
66
  },
67
67
  "devDependencies": {
68
+ "@playwright/test": "^1.40.0",
68
69
  "@types/node": "^20.11.0",
70
+ "@types/pixelmatch": "^5.2.6",
71
+ "@types/pngjs": "^6.0.5",
69
72
  "@typescript-eslint/eslint-plugin": "^8.19.1",
70
73
  "@typescript-eslint/parser": "^8.19.1",
71
74
  "@vitest/coverage-v8": "^3.1.3",
@@ -74,6 +77,8 @@
74
77
  "husky": "^9.1.7",
75
78
  "knip": "^5.45.3",
76
79
  "lint-staged": "^15.2.11",
80
+ "pixelmatch": "^5.3.0",
81
+ "pngjs": "^7.0.0",
77
82
  "prettier": "^3.4.2",
78
83
  "tsx": "^4.7.0",
79
84
  "typescript": "^5.3.0",