gm-oc 2.0.394 → 2.0.395
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/package.json +1 -1
- package/skills/browser/SKILL.md +83 -29
package/package.json
CHANGED
package/skills/browser/SKILL.md
CHANGED
|
@@ -10,10 +10,20 @@ allowed-tools: Bash(browser:*), Bash(exec:browser*)
|
|
|
10
10
|
|
|
11
11
|
**Session commands** (`browser:` prefix) — manage multi-step sessions via playwriter CLI. Each `browser:` block runs its commands sequentially.
|
|
12
12
|
|
|
13
|
-
**JS execution** (`exec:browser`) — run JavaScript directly against `page`. State persists across calls.
|
|
13
|
+
**JS execution** (`exec:browser`) — run JavaScript directly against `page`. State persists across calls via `state` global.
|
|
14
14
|
|
|
15
15
|
**CRITICAL**: Never mix these two pathways. Each `browser:` block is a separate Bash call. Each `exec:browser` block is a separate Bash call.
|
|
16
16
|
|
|
17
|
+
## 15-Second Ceiling — How It Works
|
|
18
|
+
|
|
19
|
+
Every `exec:browser` call has a 15s live window. During that window, all stdout/stderr is streamed to you in real time. After 15s the task backgrounds and you receive:
|
|
20
|
+
- All output produced so far (live drain)
|
|
21
|
+
- A task ID with `plugkit sleep/status/close` instructions
|
|
22
|
+
|
|
23
|
+
**The task keeps running.** Every subsequent plugkit interaction automatically drains all running browser tasks — you will see new output without asking.
|
|
24
|
+
|
|
25
|
+
**Never use `await new Promise(r => setTimeout(r, N))` with N > 10000.** Use short poll loops instead (see patterns below).
|
|
26
|
+
|
|
17
27
|
## Session Pathway (`browser:`)
|
|
18
28
|
|
|
19
29
|
Create a session first, use `--direct` for CDP mode (requires Chrome with remote debugging):
|
|
@@ -83,14 +93,55 @@ Never add shell quoting — write plain JavaScript directly.
|
|
|
83
93
|
|
|
84
94
|
## Core Workflow
|
|
85
95
|
|
|
86
|
-
1. **
|
|
87
|
-
2. **
|
|
88
|
-
3. **
|
|
89
|
-
4. **
|
|
90
|
-
|
|
96
|
+
1. **Navigate**: `exec:browser\nawait page.goto('url')` — session auto-created on first call
|
|
97
|
+
2. **Snapshot**: `exec:browser\nawait snapshot({ page })`
|
|
98
|
+
3. **Interact**: click, fill, type in subsequent `exec:browser` calls
|
|
99
|
+
4. **Extract data**: `exec:browser\nconsole.log(await page.evaluate(() => document.title))`
|
|
100
|
+
|
|
101
|
+
## Long-Running Operations — Poll Pattern
|
|
102
|
+
|
|
103
|
+
For operations that take >10s (model loading, network fetches, animations):
|
|
104
|
+
|
|
105
|
+
**Step 1** — set up listener and kick off the operation:
|
|
106
|
+
```
|
|
107
|
+
exec:browser
|
|
108
|
+
state.done = false
|
|
109
|
+
state.result = null
|
|
110
|
+
page.on('console', msg => {
|
|
111
|
+
const t = msg.text()
|
|
112
|
+
if (t.includes('loaded') || t.includes('ready')) { state.done = true; state.result = t }
|
|
113
|
+
})
|
|
114
|
+
await page.click('#start-button')
|
|
115
|
+
console.log('started, waiting...')
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Step 2** — poll in short bursts (this will background after 15s and keep draining):
|
|
119
|
+
```
|
|
120
|
+
exec:browser
|
|
121
|
+
const start = Date.now()
|
|
122
|
+
while (!state.done && Date.now() - start < 12000) {
|
|
123
|
+
await new Promise(r => setTimeout(r, 500))
|
|
124
|
+
}
|
|
125
|
+
console.log('done:', state.done, 'result:', state.result)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
If step 2 backgrounds (takes >15s), every subsequent plugkit call will drain its output automatically. When you see the result in the drain log, close the task:
|
|
129
|
+
```
|
|
130
|
+
exec:close
|
|
131
|
+
task_N
|
|
132
|
+
```
|
|
91
133
|
|
|
92
134
|
## Common Patterns
|
|
93
135
|
|
|
136
|
+
### Navigate and check current URL/status
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
exec:browser
|
|
140
|
+
await page.goto('https://example.com')
|
|
141
|
+
console.log('URL:', page.url())
|
|
142
|
+
console.log('title:', await page.title())
|
|
143
|
+
```
|
|
144
|
+
|
|
94
145
|
### Screenshot
|
|
95
146
|
|
|
96
147
|
```
|
|
@@ -98,7 +149,7 @@ browser:
|
|
|
98
149
|
playwriter -s 1 -e 'await screenshotWithAccessibilityLabels({ page })'
|
|
99
150
|
```
|
|
100
151
|
|
|
101
|
-
### Data Extraction
|
|
152
|
+
### Data Extraction
|
|
102
153
|
|
|
103
154
|
```
|
|
104
155
|
exec:browser
|
|
@@ -106,35 +157,24 @@ const items = await page.$$eval('.product-title', els => els.map(e => e.textCont
|
|
|
106
157
|
console.log(JSON.stringify(items))
|
|
107
158
|
```
|
|
108
159
|
|
|
109
|
-
### Console Monitoring
|
|
160
|
+
### Console Monitoring — set up listener first, then poll
|
|
110
161
|
|
|
111
162
|
```
|
|
112
163
|
exec:browser
|
|
113
|
-
state.
|
|
114
|
-
|
|
115
|
-
page.on('
|
|
164
|
+
state.logs = []
|
|
165
|
+
state.errors = []
|
|
166
|
+
page.on('console', msg => state.logs.push({ type: msg.type(), text: msg.text() }))
|
|
167
|
+
page.on('pageerror', e => state.errors.push(e.message))
|
|
168
|
+
console.log('listeners attached')
|
|
116
169
|
```
|
|
117
170
|
|
|
118
171
|
```
|
|
119
172
|
exec:browser
|
|
120
|
-
console.log(JSON.stringify(state.
|
|
173
|
+
console.log('logs so far:', JSON.stringify(state.logs.slice(-20)))
|
|
174
|
+
console.log('errors:', JSON.stringify(state.errors))
|
|
121
175
|
```
|
|
122
176
|
|
|
123
|
-
### Web Worker
|
|
124
|
-
|
|
125
|
-
```
|
|
126
|
-
exec:browser
|
|
127
|
-
state.workerMsgs = []
|
|
128
|
-
for (const w of page.workers()) {
|
|
129
|
-
w.evaluate(() => {
|
|
130
|
-
const o = console.log.bind(console)
|
|
131
|
-
console.log = (...a) => { o(...a) }
|
|
132
|
-
}).catch(() => {})
|
|
133
|
-
}
|
|
134
|
-
page.on('worker', w => {
|
|
135
|
-
state.workerMsgs.push('[worker] ' + w.url())
|
|
136
|
-
})
|
|
137
|
-
```
|
|
177
|
+
### Web Worker Access
|
|
138
178
|
|
|
139
179
|
```
|
|
140
180
|
exec:browser
|
|
@@ -150,7 +190,7 @@ if (page.workers().length > 0) {
|
|
|
150
190
|
}
|
|
151
191
|
```
|
|
152
192
|
|
|
153
|
-
### Access window
|
|
193
|
+
### Access window globals
|
|
154
194
|
|
|
155
195
|
```
|
|
156
196
|
exec:browser
|
|
@@ -161,10 +201,24 @@ const result = await page.evaluate(() => JSON.stringify({
|
|
|
161
201
|
console.log(result)
|
|
162
202
|
```
|
|
163
203
|
|
|
204
|
+
### Wait for element with short poll
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
exec:browser
|
|
208
|
+
const start = Date.now()
|
|
209
|
+
while (Date.now() - start < 12000) {
|
|
210
|
+
const el = await page.$('#status')
|
|
211
|
+
if (el) { console.log('found:', await el.textContent()); break }
|
|
212
|
+
await new Promise(r => setTimeout(r, 300))
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
164
216
|
## Key Rules
|
|
165
217
|
|
|
166
218
|
- `browser:` prefix → playwriter session management (one command per block)
|
|
167
|
-
- `exec:browser` → JS in page context (multi-line JS allowed)
|
|
219
|
+
- `exec:browser` → JS in page context (multi-line JS allowed, 15s live window)
|
|
168
220
|
- Never mix pathways in the same Bash call
|
|
169
221
|
- `-e` argument: single quotes on outside, double quotes inside for JS strings
|
|
170
222
|
- One `playwriter` command per `browser:` block
|
|
223
|
+
- Never `await setTimeout(N)` with N > 10000 — use short poll loops instead
|
|
224
|
+
- All running browser tasks drain automatically on every plugkit interaction
|