opencodekit 0.16.19 → 0.16.20

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.
package/dist/index.js CHANGED
@@ -759,7 +759,7 @@ var cac = (name = "") => new CAC(name);
759
759
  // package.json
760
760
  var package_default = {
761
761
  name: "opencodekit",
762
- version: "0.16.19",
762
+ version: "0.16.20",
763
763
  description: "CLI tool for bootstrapping and managing OpenCodeKit projects",
764
764
  keywords: ["agents", "cli", "mcp", "opencode", "opencodekit", "template"],
765
765
  license: "MIT",
@@ -3,7 +3,7 @@
3
3
  "agent": {
4
4
  "build": {
5
5
  "description": "Primary development agent with full codebase access",
6
- "model": "github-copilot/claude-opus-4.6"
6
+ "model": "opencode/kimi-k2.5-free"
7
7
  },
8
8
  "compaction": {
9
9
  "description": "Session summarizer for context continuity across compactions"
@@ -193,9 +193,6 @@
193
193
  ],
194
194
  "provider": {
195
195
  "github-copilot": {
196
- "options": {
197
- "timeout": 600000
198
- },
199
196
  "models": {
200
197
  "claude-haiku-4.5": {
201
198
  "attachment": true,
@@ -260,11 +257,11 @@
260
257
  "variants": {
261
258
  "adaptive": {
262
259
  "options": {
263
- "thinking": {
264
- "type": "adaptive"
265
- },
266
260
  "output_config": {
267
261
  "effort": "high"
262
+ },
263
+ "thinking": {
264
+ "type": "adaptive"
268
265
  }
269
266
  }
270
267
  },
@@ -368,6 +365,9 @@
368
365
  }
369
366
  }
370
367
  }
368
+ },
369
+ "options": {
370
+ "timeout": 600000
371
371
  }
372
372
  },
373
373
  "kimi-for-coding": {
@@ -547,6 +547,32 @@
547
547
  }
548
548
  }
549
549
  },
550
+ "claude-opus-4-6-thinking": {
551
+ "limit": {
552
+ "context": 200000,
553
+ "output": 64000
554
+ },
555
+ "name": "Claude Opus 4 6 Thinking",
556
+ "options": {
557
+ "thinking": {
558
+ "budgetTokens": 8192,
559
+ "type": "enabled"
560
+ }
561
+ },
562
+ "reasoning": true,
563
+ "variants": {
564
+ "low": {
565
+ "thinkingConfig": {
566
+ "thinkingBudget": 8192
567
+ }
568
+ },
569
+ "max": {
570
+ "thinkingConfig": {
571
+ "thinkingBudget": 32768
572
+ }
573
+ }
574
+ }
575
+ },
550
576
  "claude-sonnet-4-5": {
551
577
  "limit": {
552
578
  "context": 200000,
@@ -0,0 +1,428 @@
1
+ ---
2
+ name: pdf-extract
3
+ description: Extract text, images, tables, and metadata from PDF files. Choose the right library based on extraction needs - text only, structured data, or complex layouts.
4
+ ---
5
+
6
+ # PDF Content Extraction
7
+
8
+ Extract content from PDF files using the best library for your specific use case.
9
+
10
+ ## Quick Decision Guide
11
+
12
+ | Use Case | Recommended Library | Why |
13
+ | --------------------------- | ------------------- | ---------------------------------- |
14
+ | Simple text extraction | `pdf-parse` (v2+) | Fast, lightweight, pure TypeScript |
15
+ | Complex layouts/coordinates | `pdfjs-dist` | Full control, precise positioning |
16
+ | Tables/tabular data | `pdf-data-parser` | Built for grid-based content |
17
+ | Forms (XFA) | `pdf-lib` + custom | Form field extraction |
18
+ | Browser + Node.js | `pdf-parse` v2 | Cross-platform, works everywhere |
19
+
20
+ ---
21
+
22
+ ## Library 1: pdf-parse (Recommended for Text)
23
+
24
+ **Best for:** Simple text extraction, metadata, fast processing
25
+
26
+ ### Installation
27
+
28
+ ```bash
29
+ npm install pdf-parse
30
+ ```
31
+
32
+ ### Basic Text Extraction
33
+
34
+ ```typescript
35
+ import { PDFParse } from "pdf-parse";
36
+ import { readFile } from "fs/promises";
37
+
38
+ async function extractText(filePath: string): Promise<string> {
39
+ const parser = new PDFParse();
40
+ const buffer = await readFile(filePath);
41
+
42
+ const result = await parser.parse(buffer);
43
+ return result.text;
44
+ }
45
+
46
+ // Usage
47
+ const text = await extractText("./document.pdf");
48
+ console.log(text);
49
+ ```
50
+
51
+ ### Extract with Metadata
52
+
53
+ ```typescript
54
+ import { PDFParse } from "pdf-parse";
55
+
56
+ async function extractWithMetadata(filePath: string) {
57
+ const parser = new PDFParse();
58
+ const buffer = await readFile(filePath);
59
+
60
+ const result = await parser.parse(buffer);
61
+
62
+ return {
63
+ text: result.text,
64
+ info: result.info, // Document metadata
65
+ numpages: result.numpages,
66
+ version: result.version,
67
+ };
68
+ }
69
+ ```
70
+
71
+ ### Extract Specific Pages
72
+
73
+ ```typescript
74
+ import { PDFParse } from "pdf-parse";
75
+
76
+ async function extractPage(filePath: string, pageNum: number) {
77
+ const parser = new PDFParse();
78
+ const buffer = await readFile(filePath);
79
+
80
+ const result = await parser.parse(buffer, {
81
+ max: pageNum,
82
+ min: pageNum,
83
+ });
84
+
85
+ return result.text;
86
+ }
87
+ ```
88
+
89
+ ### URL-based Extraction (without downloading full file)
90
+
91
+ ```typescript
92
+ import { getHeader } from "pdf-parse/node";
93
+
94
+ async function checkPDFHeaders(url: string) {
95
+ // Check file size and headers before downloading
96
+ const headers = await getHeader(url, true);
97
+ console.log(`File size: ${headers.size} bytes`);
98
+
99
+ if (headers.size > 10 * 1024 * 1024) {
100
+ console.warn("Large PDF - consider streaming");
101
+ }
102
+ }
103
+ ```
104
+
105
+ ---
106
+
107
+ ## Library 2: pdfjs-dist (Mozilla PDF.js)
108
+
109
+ **Best for:** Complex layouts, coordinates, images, page-by-page control
110
+
111
+ ### Installation
112
+
113
+ ```bash
114
+ npm install pdfjs-dist
115
+ ```
116
+
117
+ ### Basic Text Extraction with Coordinates
118
+
119
+ ```typescript
120
+ import * as pdfjsLib from "pdfjs-dist/legacy/build/pdf.mjs";
121
+ import { readFile } from "fs/promises";
122
+ import path from "path";
123
+
124
+ async function extractWithCoordinates(pdfPath: string) {
125
+ const data = await readFile(pdfPath);
126
+ const dataArray = new Uint8Array(data);
127
+
128
+ const pdfDocument = await pdfjsLib.getDocument({
129
+ data: dataArray,
130
+ standardFontDataUrl: path.join(process.cwd(), "node_modules/pdfjs-dist/standard_fonts/"),
131
+ }).promise;
132
+
133
+ const numPages = pdfDocument.numPages;
134
+ const results = [];
135
+
136
+ for (let pageNum = 1; pageNum <= numPages; pageNum++) {
137
+ const page = await pdfDocument.getPage(pageNum);
138
+ const textContent = await page.getTextContent();
139
+
140
+ const pageText = textContent.items.map((item: any) => ({
141
+ text: item.str,
142
+ x: item.transform[4],
143
+ y: item.transform[5],
144
+ font: item.fontName,
145
+ width: item.width,
146
+ height: item.height,
147
+ }));
148
+
149
+ results.push({
150
+ page: pageNum,
151
+ items: pageText,
152
+ });
153
+ }
154
+
155
+ return results;
156
+ }
157
+ ```
158
+
159
+ ### Extract Images from PDF
160
+
161
+ ```typescript
162
+ import * as pdfjsLib from "pdfjs-dist/legacy/build/pdf.mjs";
163
+
164
+ async function extractImages(pdfPath: string) {
165
+ const data = await readFile(pdfPath);
166
+ const pdfDocument = await pdfjsLib.getDocument({ data: new Uint8Array(data) }).promise;
167
+
168
+ const images = [];
169
+
170
+ for (let pageNum = 1; pageNum <= pdfDocument.numPages; pageNum++) {
171
+ const page = await pdfDocument.getPage(pageNum);
172
+ const ops = await page.getOperatorList();
173
+
174
+ for (let i = 0; i < ops.fnArray.length; i++) {
175
+ if (ops.fnArray[i] === pdfjsLib.OPS.paintImageXObject) {
176
+ const imageName = ops.argsArray[i][0];
177
+ const image = await page.objs.get(imageName);
178
+
179
+ images.push({
180
+ page: pageNum,
181
+ name: imageName,
182
+ width: image.width,
183
+ height: image.height,
184
+ data: image.data, // Raw image data
185
+ });
186
+ }
187
+ }
188
+ }
189
+
190
+ return images;
191
+ }
192
+ ```
193
+
194
+ ### Render Page to Image
195
+
196
+ ```typescript
197
+ import * as pdfjsLib from "pdfjs-dist/legacy/build/pdf.mjs";
198
+ import { createCanvas } from "canvas";
199
+ import { writeFile } from "fs/promises";
200
+
201
+ async function renderPageToImage(pdfPath: string, pageNum: number, outputPath: string) {
202
+ const data = await readFile(pdfPath);
203
+ const pdfDocument = await pdfjsLib.getDocument({ data: new Uint8Array(data) }).promise;
204
+
205
+ const page = await pdfDocument.getPage(pageNum);
206
+ const viewport = page.getViewport({ scale: 2.0 }); // Higher scale = better quality
207
+
208
+ const canvas = createCanvas(viewport.width, viewport.height);
209
+ const context = canvas.getContext("2d");
210
+
211
+ await page.render({
212
+ canvasContext: context,
213
+ viewport: viewport,
214
+ }).promise;
215
+
216
+ const buffer = canvas.toBuffer("image/png");
217
+ await writeFile(outputPath, buffer);
218
+
219
+ console.log(`Page ${pageNum} saved to ${outputPath}`);
220
+ }
221
+ ```
222
+
223
+ ---
224
+
225
+ ## Library 3: pdf-data-parser (Tables)
226
+
227
+ **Best for:** Tabular data, structured grid content
228
+
229
+ ### Installation
230
+
231
+ ```bash
232
+ npm install pdf-data-parser
233
+ ```
234
+
235
+ ### Extract Tables
236
+
237
+ ```typescript
238
+ import { PdfDataParser } from "pdf-data-parser";
239
+
240
+ async function extractTables(pdfPath: string) {
241
+ const parser = new PdfDataParser({
242
+ url: pdfPath,
243
+ // Options
244
+ heading: "Table Title", // Filter to specific table
245
+ cells: 3, // Minimum cells per row
246
+ headers: ["Name", "Amount"], // Expected headers
247
+ repeating: false, // Handle repeating headers
248
+ });
249
+
250
+ const rows = await parser.parse();
251
+ return rows; // Array of arrays
252
+ }
253
+ ```
254
+
255
+ ### Stream Large PDFs
256
+
257
+ ```typescript
258
+ import { PdfDataReader } from "pdf-data-parser";
259
+ import { createWriteStream } from "fs";
260
+
261
+ async function streamToCSV(pdfPath: string, outputPath: string) {
262
+ const reader = new PdfDataReader({
263
+ url: pdfPath,
264
+ cells: 2,
265
+ });
266
+
267
+ const output = createWriteStream(outputPath);
268
+
269
+ reader.on("data", (row: string[]) => {
270
+ output.write(row.join(",") + "\n");
271
+ });
272
+
273
+ reader.on("end", () => {
274
+ output.end();
275
+ console.log("CSV created");
276
+ });
277
+ }
278
+ ```
279
+
280
+ ---
281
+
282
+ ## Best Practices
283
+
284
+ ### 1. Error Handling
285
+
286
+ ```typescript
287
+ async function safeExtract(filePath: string) {
288
+ try {
289
+ const buffer = await readFile(filePath);
290
+
291
+ // Validate PDF header
292
+ const header = buffer.slice(0, 5).toString();
293
+ if (header !== "%PDF-") {
294
+ throw new Error("Invalid PDF file");
295
+ }
296
+
297
+ const result = await parser.parse(buffer);
298
+ return result;
299
+ } catch (error) {
300
+ if (error.message.includes("password")) {
301
+ throw new Error("PDF is password protected");
302
+ }
303
+ if (error.message.includes("damaged")) {
304
+ throw new Error("PDF is corrupted");
305
+ }
306
+ throw error;
307
+ }
308
+ }
309
+ ```
310
+
311
+ ### 2. Memory Management (Large Files)
312
+
313
+ ```typescript
314
+ // For large PDFs, process page by page
315
+ async function extractLargePDF(pdfPath: string) {
316
+ const data = await readFile(pdfPath);
317
+ const pdfDocument = await pdfjsLib.getDocument({ data: new Uint8Array(data) }).promise;
318
+
319
+ // Don't load all pages at once
320
+ for (let i = 1; i <= pdfDocument.numPages; i++) {
321
+ const page = await pdfDocument.getPage(i);
322
+ const text = await page.getTextContent();
323
+
324
+ // Process immediately, don't accumulate
325
+ await processPageText(text);
326
+
327
+ // Clean up
328
+ page.cleanup();
329
+ }
330
+ }
331
+ ```
332
+
333
+ ### 3. Text Cleaning
334
+
335
+ ```typescript
336
+ function cleanExtractedText(text: string): string {
337
+ return text
338
+ .replace(/\s+/g, " ") // Normalize whitespace
339
+ .replace(/[^\x20-\x7E\n]/g, "") // Remove non-printable chars
340
+ .trim();
341
+ }
342
+ ```
343
+
344
+ ### 4. Performance Tips
345
+
346
+ ```typescript
347
+ // Parallel extraction for multiple files
348
+ async function extractMultiple(files: string[]) {
349
+ const results = await Promise.all(
350
+ files.map((file) => extractText(file).catch((err) => ({ file, error: err }))),
351
+ );
352
+ return results;
353
+ }
354
+
355
+ // Use streams for very large files
356
+ import { createReadStream } from "fs";
357
+ import { PdfDataReader } from "pdf-data-parser";
358
+ ```
359
+
360
+ ---
361
+
362
+ ## Common Issues & Solutions
363
+
364
+ | Issue | Cause | Solution |
365
+ | -------------------- | --------------------- | ------------------------------------- |
366
+ | Text appears garbled | Encoding issue | Use pdfjs-dist with explicit encoding |
367
+ | Missing text | Scanned image PDF | Use OCR (Tesseract) before extraction |
368
+ | Out of memory | Large PDF | Stream processing, page-by-page |
369
+ | Password error | Encrypted PDF | Use `pdf-lib` to decrypt first |
370
+ | Missing coordinates | Wrong library | Use pdfjs-dist for positioning |
371
+ | Table structure lost | Plain text extraction | Use pdf-data-parser |
372
+ | Font warnings | Missing fonts | Set `standardFontDataUrl` option |
373
+
374
+ ---
375
+
376
+ ## Complete Example: Document Processor
377
+
378
+ ```typescript
379
+ import { PDFParse } from "pdf-parse";
380
+ import { readFile } from "fs/promises";
381
+
382
+ interface DocumentResult {
383
+ text: string;
384
+ metadata: {
385
+ title?: string;
386
+ author?: string;
387
+ pages: number;
388
+ creationDate?: Date;
389
+ };
390
+ summary: string;
391
+ }
392
+
393
+ async function processDocument(filePath: string): Promise<DocumentResult> {
394
+ const parser = new PDFParse();
395
+ const buffer = await readFile(filePath);
396
+
397
+ const result = await parser.parse(buffer);
398
+
399
+ // Generate summary (first 500 chars)
400
+ const summary = result.text.replace(/\s+/g, " ").slice(0, 500).trim() + "...";
401
+
402
+ return {
403
+ text: result.text,
404
+ metadata: {
405
+ title: result.info?.Title,
406
+ author: result.info?.Author,
407
+ pages: result.numpages,
408
+ creationDate: result.info?.CreationDate ? new Date(result.info.CreationDate) : undefined,
409
+ },
410
+ summary,
411
+ };
412
+ }
413
+
414
+ // Usage
415
+ const doc = await processDocument("./report.pdf");
416
+ console.log(`Document: ${doc.metadata.title}`);
417
+ console.log(`Pages: ${doc.metadata.pages}`);
418
+ console.log(`Summary: ${doc.summary}`);
419
+ ```
420
+
421
+ ---
422
+
423
+ ## References
424
+
425
+ - [pdf-parse npm](https://www.npmjs.com/package/pdf-parse)
426
+ - [pdfjs-dist docs](https://mozilla.github.io/pdf.js/)
427
+ - [pdf-data-parser GitHub](https://github.com/drewletcher/pdf-data-parser)
428
+ - [pdf-lib GitHub](https://github.com/Hopding/pdf-lib)
@@ -1,112 +1,310 @@
1
1
  ---
2
2
  name: playwright
3
- description: Browser automation with Playwright MCP. Test pages, fill forms, take screenshots, check responsive design, validate UX, test login flows. Use when user wants to test websites or automate browser interactions.
3
+ description: Browser automation for testing, screenshots, form validation, and UX verification. Uses Playwright CLI for token-efficient automation, with MCP fallback for complex exploratory workflows.
4
4
  ---
5
5
 
6
- # Playwright Browser Automation (MCP)
6
+ # Playwright Browser Automation
7
7
 
8
- Browser automation via Playwright MCP server for testing and automation.
8
+ Browser automation via **Playwright CLI** (primary) and **Playwright MCP** (fallback for complex workflows).
9
9
 
10
- ## Available Tools
10
+ ## Quick Decision
11
11
 
12
- - `browser_navigate` - Navigate to URL
13
- - `browser_snapshot` - Get page accessibility snapshot with element refs
14
- - `browser_take_screenshot` - Capture screenshot
15
- - `browser_click` - Click element by ref
16
- - `browser_type` - Type text (appends to existing)
17
- - `browser_fill` - Fill input (clears first, then types)
18
- - `browser_wait_for` - Wait for text or selector
19
- - `browser_resize` - Resize viewport or emulate device
12
+ | Scenario | Use |
13
+ | --------------------------------------------------- | ------- |
14
+ | Quick screenshots, simple forms, token efficiency | **CLI** |
15
+ | Complex exploratory testing, self-healing workflows | **MCP** |
16
+
17
+ ---
20
18
 
21
- ## Workflow
19
+ ## CLI Mode (Recommended)
22
20
 
23
- 1. **Navigate** to the target URL using `browser_navigate`
24
- 2. **Snapshot** to see page structure and element refs using `browser_snapshot`
25
- 3. **Interact** using element refs from snapshot (`browser_click`, `browser_fill`)
26
- 4. **Screenshot** to capture results using `browser_take_screenshot`
21
+ The CLI approach is **token-efficient** - no large schemas or verbose accessibility trees in context. Best for most automation tasks.
27
22
 
28
- ## Quick Start
23
+ ### Installation
29
24
 
25
+ ```bash
26
+ npm install -g @playwright/cli@latest
27
+ playwright-cli install --skills # Optional: install for Claude/Copilot
30
28
  ```
31
- # Navigate to page
32
- skill_mcp(skill_name="playwright", tool_name="browser_navigate", arguments='{"url": "https://example.com"}')
33
29
 
34
- # Get page structure with element refs
35
- skill_mcp(skill_name="playwright", tool_name="browser_snapshot")
30
+ ### Core Workflow
36
31
 
37
- # Click element (use ref from snapshot)
38
- skill_mcp(skill_name="playwright", tool_name="browser_click", arguments='{"element": "Submit button", "ref": "e123"}')
32
+ ```
33
+ # 1. Open browser and navigate
34
+ bash({ command: "playwright-cli open https://example.com" })
35
+
36
+ # 2. Get element refs (snapshot)
37
+ bash({ command: "playwright-cli snapshot" })
39
38
 
40
- # Fill input field
41
- skill_mcp(skill_name="playwright", tool_name="browser_fill", arguments='{"element": "Email", "ref": "e456", "text": "test@example.com"}')
39
+ # 3. Interact using refs
40
+ bash({ command: "playwright-cli fill e12 'test@example.com'" })
41
+ bash({ command: "playwright-cli click e34" })
42
42
 
43
- # Take screenshot
44
- skill_mcp(skill_name="playwright", tool_name="browser_take_screenshot", arguments='{"filename": "/tmp/result.png"}')
43
+ # 4. Screenshot
44
+ bash({ command: "playwright-cli screenshot --filename=/tmp/result.png" })
45
45
  ```
46
46
 
47
- ## Examples
47
+ ### Commands Reference
48
+
49
+ #### Navigation
50
+
51
+ | Command | Description |
52
+ | ------------ | ---------------------------------------- |
53
+ | `open [url]` | Open browser, optionally navigate to URL |
54
+ | `goto <url>` | Navigate to URL |
55
+ | `close` | Close the page/browser |
56
+ | `go-back` | Go back to previous page |
57
+ | `go-forward` | Go forward to next page |
58
+ | `reload` | Reload current page |
59
+
60
+ #### Interaction
61
+
62
+ | Command | Description |
63
+ | -------------------------- | ----------------------------------------- |
64
+ | `snapshot` | Capture page snapshot to get element refs |
65
+ | `type <text>` | Type text into focused element |
66
+ | `fill <ref> <text>` | Fill text into specific element |
67
+ | `click <ref> [button]` | Click element (left/right/middle) |
68
+ | `dblclick <ref>` | Double-click element |
69
+ | `hover <ref>` | Hover over element |
70
+ | `drag <startRef> <endRef>` | Drag and drop |
71
+ | `select <ref> <value>` | Select dropdown option |
72
+ | `check <ref>` | Check checkbox/radio |
73
+ | `uncheck <ref>` | Uncheck checkbox |
74
+ | `upload <file>` | Upload file(s) |
75
+
76
+ #### Keyboard
77
+
78
+ | Command | Description |
79
+ | --------------- | -------------------------------------- |
80
+ | `press <key>` | Press key (e.g., `Enter`, `ArrowLeft`) |
81
+ | `keydown <key>` | Hold key down |
82
+ | `keyup <key>` | Release key |
48
83
 
49
- ### Test Responsive Design
84
+ #### Screenshots & PDF
50
85
 
86
+ | Command | Description |
87
+ | ------------------------------------ | -------------------------- |
88
+ | `screenshot [ref]` | Screenshot page or element |
89
+ | `screenshot --filename=/tmp/out.png` | Save to specific path |
90
+ | `pdf` | Save page as PDF |
91
+ | `pdf --filename=page.pdf` | Save PDF to specific path |
92
+
93
+ #### Tabs
94
+
95
+ | Command | Description |
96
+ | -------------------- | -------------- |
97
+ | `tab-list` | List all tabs |
98
+ | `tab-new [url]` | Create new tab |
99
+ | `tab-close [index]` | Close tab |
100
+ | `tab-select <index>` | Switch to tab |
101
+
102
+ #### Storage
103
+
104
+ | Command | Description |
105
+ | -------------------------------- | ------------------------------- |
106
+ | `cookie-list` | List cookies |
107
+ | `cookie-get <name>` | Get cookie value |
108
+ | `cookie-set <name> <value>` | Set cookie |
109
+ | `cookie-delete <name>` | Delete cookie |
110
+ | `cookie-clear` | Clear all cookies |
111
+ | `localstorage-list` | List localStorage |
112
+ | `localstorage-get <key>` | Get localStorage value |
113
+ | `localstorage-set <key> <value>` | Set localStorage |
114
+ | `sessionstorage-*` | Same pattern for sessionStorage |
115
+
116
+ #### Network
117
+
118
+ | Command | Description |
119
+ | ------------------- | --------------------- |
120
+ | `route <pattern>` | Mock network requests |
121
+ | `route-list` | List active routes |
122
+ | `unroute [pattern]` | Remove route(s) |
123
+
124
+ #### DevTools
125
+
126
+ | Command | Description |
127
+ | ----------------------- | ----------------------------------- |
128
+ | `console [min-level]` | List console messages |
129
+ | `network` | List network requests |
130
+ | `eval <func> [ref]` | Evaluate JavaScript on page/element |
131
+ | `run-code <code>` | Run Playwright code snippet |
132
+ | `tracing-start` | Start trace recording |
133
+ | `tracing-stop` | Stop trace recording |
134
+ | `video-start` | Start video recording |
135
+ | `video-stop [filename]` | Stop video recording |
136
+
137
+ ### CLI Options
138
+
139
+ ```bash
140
+ # Headless mode
141
+ playwright-cli open https://example.com --headless
142
+
143
+ # Choose browser
144
+ playwright-cli open https://example.com --browser=firefox
145
+
146
+ # Emulate device
147
+ playwright-cli open https://example.com --device="iPhone 14"
148
+
149
+ # Named session (isolated browser)
150
+ playwright-cli -s=project1 open https://example.com
151
+
152
+ # See all options
153
+ playwright-cli --help
51
154
  ```
52
- # Navigate
53
- skill_mcp(skill_name="playwright", tool_name="browser_navigate", arguments='{"url": "http://localhost:3000"}')
54
155
 
55
- # Desktop
56
- skill_mcp(skill_name="playwright", tool_name="browser_resize", arguments='{"width": 1920, "height": 1080}')
57
- skill_mcp(skill_name="playwright", tool_name="browser_take_screenshot", arguments='{"filename": "/tmp/desktop.png"}')
156
+ ### CLI Examples
157
+
158
+ #### Test Responsive Design
58
159
 
59
- # Mobile
60
- skill_mcp(skill_name="playwright", tool_name="browser_resize", arguments='{"device": "iPhone 13"}')
61
- skill_mcp(skill_name="playwright", tool_name="browser_take_screenshot", arguments='{"filename": "/tmp/mobile.png"}')
160
+ ```typescript
161
+ // Desktop
162
+ bash({ command: "playwright-cli open http://localhost:3000" });
163
+ bash({ command: "playwright-cli resize 1920 1080" });
164
+ bash({ command: "playwright-cli screenshot --filename=/tmp/desktop.png" });
165
+
166
+ // Mobile
167
+ bash({ command: "playwright-cli resize 390 844" }); // iPhone 14
168
+ bash({ command: "playwright-cli screenshot --filename=/tmp/mobile.png" });
62
169
  ```
63
170
 
64
- ### Fill a Form
171
+ #### Fill a Form
172
+
173
+ ```typescript
174
+ bash({ command: "playwright-cli open http://localhost:3000/contact" });
175
+
176
+ // Get snapshot to see element refs
177
+ bash({ command: "playwright-cli snapshot" });
178
+
179
+ // Fill using refs from snapshot output
180
+ bash({ command: "playwright-cli fill e12 'John Doe'" });
181
+ bash({ command: "playwright-cli fill e34 'john@example.com'" });
182
+ bash({ command: "playwright-cli click e56" }); // Submit button
65
183
 
184
+ // Wait for confirmation
185
+ bash({ command: "playwright-cli eval 'document.body.innerText.includes(\"Thank you\")'" });
66
186
  ```
67
- # Navigate to form
68
- skill_mcp(skill_name="playwright", tool_name="browser_navigate", arguments='{"url": "http://localhost:3000/contact"}')
69
187
 
70
- # Get element refs
71
- skill_mcp(skill_name="playwright", tool_name="browser_snapshot")
188
+ #### Multi-Step Login Flow
72
189
 
73
- # Fill fields (use refs from snapshot)
74
- skill_mcp(skill_name="playwright", tool_name="browser_fill", arguments='{"element": "Name", "ref": "e12", "text": "John Doe"}')
75
- skill_mcp(skill_name="playwright", tool_name="browser_fill", arguments='{"element": "Email", "ref": "e34", "text": "john@example.com"}')
190
+ ```typescript
191
+ bash({ command: "playwright-cli open https://app.example.com/login" });
192
+ bash({ command: "playwright-cli snapshot" });
76
193
 
77
- # Submit
78
- skill_mcp(skill_name="playwright", tool_name="browser_click", arguments='{"element": "Submit", "ref": "e56"}')
194
+ bash({ command: "playwright-cli fill e10 'username'" });
195
+ bash({ command: "playwright-cli fill e12 'password'" });
196
+ bash({ command: "playwright-cli click e15" });
79
197
 
80
- # Wait for confirmation
81
- skill_mcp(skill_name="playwright", tool_name="browser_wait_for", arguments='{"text": "Thank you", "timeout": 5000}')
198
+ // Verify logged in
199
+ bash({ command: "playwright-cli eval 'document.querySelector(\".dashboard\") !== null'" });
200
+ bash({ command: "playwright-cli screenshot --filename=/tmp/logged-in.png" });
82
201
  ```
83
202
 
84
- ## Tips
203
+ #### Session Management
204
+
205
+ ```typescript
206
+ // List all browser sessions
207
+ bash({ command: "playwright-cli list" });
208
+
209
+ // Use named session
210
+ bash({ command: "playwright-cli -s=project1 open https://example.com" });
211
+
212
+ // Close specific session
213
+ bash({ command: "playwright-cli -s=project1 close" });
214
+
215
+ // Close all browsers
216
+ bash({ command: "playwright-cli close-all" });
217
+ ```
218
+
219
+ ---
220
+
221
+ ## MCP Mode (Fallback)
222
+
223
+ Use MCP for complex exploratory workflows or when you need persistent browser state with rich introspection.
224
+
225
+ ### Tools (8 Essential)
226
+
227
+ - `browser_navigate` - Navigate to URL
228
+ - `browser_snapshot` - Get accessibility snapshot with element refs
229
+ - `browser_take_screenshot` - Capture screenshot
230
+ - `browser_click` - Click element by ref
231
+ - `browser_type` - Type text (appends)
232
+ - `browser_fill` - Fill input (clears first, then types)
233
+ - `browser_wait_for` - Wait for text or selector
234
+ - `browser_resize` - Resize viewport or emulate device
85
235
 
86
- - **Always snapshot first** to get element refs before interacting
87
- - **Use descriptive element names** in click/fill for clarity
88
- - **Save screenshots to /tmp** for easy access
89
- - **Use device presets** for accurate mobile emulation
90
- - **Chain wait_for** after navigation for dynamic pages
236
+ ### MCP Workflow
91
237
 
92
- ## Server Options
238
+ ```typescript
239
+ // Navigate
240
+ skill_mcp(
241
+ (skill_name = "playwright"),
242
+ (tool_name = "browser_navigate"),
243
+ (arguments = '{"url": "https://example.com"}'),
244
+ );
93
245
 
94
- For advanced usage, modify `mcp.json`:
246
+ // Get element refs
247
+ skill_mcp((skill_name = "playwright"), (tool_name = "browser_snapshot"));
248
+
249
+ // Interact
250
+ skill_mcp(
251
+ (skill_name = "playwright"),
252
+ (tool_name = "browser_click"),
253
+ (arguments = '{"element": "Submit", "ref": "e12"}'),
254
+ );
255
+
256
+ // Screenshot
257
+ skill_mcp(
258
+ (skill_name = "playwright"),
259
+ (tool_name = "browser_take_screenshot"),
260
+ (arguments = '{"filename": "/tmp/result.png"}'),
261
+ );
262
+ ```
263
+
264
+ ### MCP Configuration
95
265
 
96
266
  ```json
97
267
  {
98
268
  "playwright": {
99
269
  "command": "npx",
100
- "args": ["@playwright/mcp@latest", "--headless", "--browser=firefox"],
101
- "includeTools": ["browser_navigate", "browser_snapshot", "..."]
270
+ "args": ["@playwright/mcp@latest"],
271
+ "includeTools": [
272
+ "browser_navigate",
273
+ "browser_snapshot",
274
+ "browser_take_screenshot",
275
+ "browser_click",
276
+ "browser_type",
277
+ "browser_fill",
278
+ "browser_wait_for",
279
+ "browser_resize"
280
+ ]
102
281
  }
103
282
  }
104
283
  ```
105
284
 
106
- Common options:
285
+ ---
286
+
287
+ ## Best Practices
288
+
289
+ 1. **Default to CLI** for token efficiency
290
+ 2. **Snapshot before interact** - always get element refs first
291
+ 3. **Use named sessions** (`-s=`) for isolated browser contexts
292
+ 4. **Save outputs to /tmp** for easy access and cleanup
293
+ 5. **Check console/network** for debugging: `playwright-cli console error`
294
+ 6. **Use eval for custom checks** when built-in commands aren't enough
295
+
296
+ ## Troubleshooting
297
+
298
+ | Issue | Solution |
299
+ | ------------------- | ------------------------------------------------ |
300
+ | Element not found | Re-run snapshot to get fresh refs |
301
+ | Page not loading | Check network with `playwright-cli network` |
302
+ | Timing issues | Use `eval` to check conditions before proceeding |
303
+ | Session conflicts | Use named sessions (`-s=project1`) |
304
+ | Browser won't close | `playwright-cli kill-all` as last resort |
107
305
 
108
- - `--headless` - Run without visible browser
109
- - `--browser=chrome|firefox|webkit` - Choose browser
110
- - `--device="iPhone 13"` - Emulate device
306
+ ## References
111
307
 
112
- > **Note**: This skill loads 8 essential tools. For full 17+ tools (tabs, PDF, evaluate, drag), modify `mcp.json` to add more tools to `includeTools`.
308
+ - [Playwright CLI GitHub](https://github.com/microsoft/playwright-cli)
309
+ - [Playwright MCP GitHub](https://github.com/microsoft/playwright-mcp)
310
+ - [Playwright Docs](https://playwright.dev)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencodekit",
3
- "version": "0.16.19",
3
+ "version": "0.16.20",
4
4
  "description": "CLI tool for bootstrapping and managing OpenCodeKit projects",
5
5
  "keywords": ["agents", "cli", "mcp", "opencode", "opencodekit", "template"],
6
6
  "license": "MIT",