lazycodex-ai 5.1.65 → 5.1.68
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/cli/index.js +210 -158
- package/dist/cli/service-auth/account-home.d.ts +47 -0
- package/dist/cli/service-auth/account-home.fixture.d.ts +1 -0
- package/dist/cli/service-auth/credential-lock.d.ts +2 -0
- package/dist/cli/service-auth/index.d.ts +1 -1
- package/dist/cli-node/index.js +210 -158
- package/package.json +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +12 -12
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/skills/browser/ATTRIBUTION.md +11 -7
- package/packages/omo-codex/plugin/skills/browser/SKILL.md +21 -6
- package/packages/omo-codex/plugin/skills/browser/references/commands.md +41 -4
- package/packages/omo-codex/plugin/skills/browser/references/owned-engine/frames-and-humans.md +15 -4
- package/packages/omo-codex/plugin/skills/browser/references/recipes/1password.md +4 -2
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/LICENSE +21 -0
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +4 -3
- package/packages/omo-codex/plugin/skills/debugging/references/tools/browser-qa.md +4 -3
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +6 -6
- package/packages/omo-codex/plugin/skills/ulw-research/references/research-collection.md +2 -2
- package/packages/omo-codex/plugin/skills/visual-qa/references/browser-setup.md +5 -4
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +3 -3
- package/packages/shared-skills/skills/browser/ATTRIBUTION.md +11 -7
- package/packages/shared-skills/skills/browser/SKILL.md +21 -6
- package/packages/shared-skills/skills/browser/references/commands.md +41 -4
- package/packages/shared-skills/skills/browser/references/owned-engine/frames-and-humans.md +15 -4
- package/packages/shared-skills/skills/browser/references/recipes/1password.md +4 -2
- package/packages/shared-skills/skills/browser/runtime/omowright/LICENSE +21 -0
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +4 -3
- package/packages/shared-skills/skills/debugging/references/tools/browser-qa.md +4 -3
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +1 -1
- package/packages/shared-skills/skills/ulw-research/SKILL.md +6 -6
- package/packages/shared-skills/skills/ulw-research/references/research-collection.md +2 -2
- package/packages/shared-skills/skills/visual-qa/references/browser-setup.md +5 -4
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sisyphuslabs/omo-codex-plugin",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.68",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@sisyphuslabs/omo-codex-plugin",
|
|
9
|
-
"version": "5.1.
|
|
9
|
+
"version": "5.1.68",
|
|
10
10
|
"workspaces": [
|
|
11
11
|
"components/comment-checker",
|
|
12
12
|
"components/git-bash",
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
},
|
|
101
101
|
"components/comment-checker": {
|
|
102
102
|
"name": "@code-yeongyu/codex-comment-checker",
|
|
103
|
-
"version": "5.1.
|
|
103
|
+
"version": "5.1.68",
|
|
104
104
|
"license": "MIT",
|
|
105
105
|
"bin": {
|
|
106
106
|
"omo-comment-checker": "dist/cli.js"
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
},
|
|
123
123
|
"components/git-bash": {
|
|
124
124
|
"name": "@sisyphuslabs/codex-git-bash-hook",
|
|
125
|
-
"version": "5.1.
|
|
125
|
+
"version": "5.1.68",
|
|
126
126
|
"bin": {
|
|
127
127
|
"omo-git-bash-hook": "dist/cli.js"
|
|
128
128
|
},
|
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
},
|
|
137
137
|
"components/lazycodex-executor-verify": {
|
|
138
138
|
"name": "@code-yeongyu/codex-lazycodex-executor-verify",
|
|
139
|
-
"version": "5.1.
|
|
139
|
+
"version": "5.1.68",
|
|
140
140
|
"license": "MIT",
|
|
141
141
|
"bin": {
|
|
142
142
|
"lazycodex-executor-verify": "dist/cli.js"
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
},
|
|
155
155
|
"components/lsp": {
|
|
156
156
|
"name": "@code-yeongyu/codex-lsp",
|
|
157
|
-
"version": "5.1.
|
|
157
|
+
"version": "5.1.68",
|
|
158
158
|
"license": "MIT",
|
|
159
159
|
"dependencies": {
|
|
160
160
|
"@code-yeongyu/lsp-daemon": "file:../../../../lsp-daemon",
|
|
@@ -176,7 +176,7 @@
|
|
|
176
176
|
},
|
|
177
177
|
"components/rules": {
|
|
178
178
|
"name": "@code-yeongyu/codex-rules",
|
|
179
|
-
"version": "5.1.
|
|
179
|
+
"version": "5.1.68",
|
|
180
180
|
"license": "MIT",
|
|
181
181
|
"dependencies": {
|
|
182
182
|
"picomatch": "^4.0.7"
|
|
@@ -199,7 +199,7 @@
|
|
|
199
199
|
},
|
|
200
200
|
"components/teammode": {
|
|
201
201
|
"name": "@sisyphuslabs/codex-teammode",
|
|
202
|
-
"version": "5.1.
|
|
202
|
+
"version": "5.1.68",
|
|
203
203
|
"devDependencies": {
|
|
204
204
|
"@types/node": "^26.6.2",
|
|
205
205
|
"@vitest/coverage-v8": "5.0.1",
|
|
@@ -213,7 +213,7 @@
|
|
|
213
213
|
},
|
|
214
214
|
"components/telemetry": {
|
|
215
215
|
"name": "@code-yeongyu/codex-telemetry",
|
|
216
|
-
"version": "5.1.
|
|
216
|
+
"version": "5.1.68",
|
|
217
217
|
"license": "MIT",
|
|
218
218
|
"bin": {
|
|
219
219
|
"omo-telemetry": "dist/cli.js"
|
|
@@ -232,7 +232,7 @@
|
|
|
232
232
|
},
|
|
233
233
|
"components/ultrawork": {
|
|
234
234
|
"name": "@code-yeongyu/codex-ultrawork",
|
|
235
|
-
"version": "5.1.
|
|
235
|
+
"version": "5.1.68",
|
|
236
236
|
"license": "MIT",
|
|
237
237
|
"bin": {
|
|
238
238
|
"omo-ultrawork": "dist/cli.js"
|
|
@@ -251,7 +251,7 @@
|
|
|
251
251
|
},
|
|
252
252
|
"components/ulw-execute-continuation": {
|
|
253
253
|
"name": "@code-yeongyu/codex-ulw-execute-continuation",
|
|
254
|
-
"version": "5.1.
|
|
254
|
+
"version": "5.1.68",
|
|
255
255
|
"license": "MIT",
|
|
256
256
|
"bin": {
|
|
257
257
|
"omo-ulw-execute-continuation": "dist/cli.js"
|
|
@@ -269,7 +269,7 @@
|
|
|
269
269
|
},
|
|
270
270
|
"components/ulw-loop": {
|
|
271
271
|
"name": "@code-yeongyu/codex-ulw-loop",
|
|
272
|
-
"version": "5.1.
|
|
272
|
+
"version": "5.1.68",
|
|
273
273
|
"license": "MIT",
|
|
274
274
|
"bin": {
|
|
275
275
|
"omo-ulw-loop": "dist/cli.js",
|
|
@@ -7,16 +7,20 @@ plus a staged copy of one library it drives.
|
|
|
7
7
|
|
|
8
8
|
Both engines this skill documents are provided by **omowright**.
|
|
9
9
|
|
|
10
|
-
- Upstream: the `omowright`
|
|
11
|
-
|
|
10
|
+
- Upstream: the `omowright` package (npm, source on GitHub). The root `package.json` declares it
|
|
11
|
+
as a semver range (`^0.3.0` today); the exact version installed is recorded in `bun.lock` and in
|
|
12
|
+
the staged `manifest.json`.
|
|
12
13
|
- License: MIT
|
|
13
14
|
- What ships here: `runtime/omowright/index.js` (the library bundled into one ESM file, including
|
|
14
|
-
its `ws` and `zod` dependencies)
|
|
15
|
-
script it reads at import time)
|
|
15
|
+
its `ws` and `zod` dependencies), `runtime/omowright/page-bundle.js` (the in-page snapshot
|
|
16
|
+
script it reads at import time) and `runtime/omowright/LICENSE` (omowright's MIT text, copied
|
|
17
|
+
verbatim), staged at build time by
|
|
16
18
|
`packages/shared-skills/stage-omowright-runtime.mjs` from the pinned root devDependency, with a
|
|
17
|
-
`manifest.json` recording the version and file digests.
|
|
18
|
-
staged files are gitignored and packed through the
|
|
19
|
-
|
|
19
|
+
`manifest.json` recording the version and file digests. Staging fails when omowright has no
|
|
20
|
+
`LICENSE`. The repository holds no copy; the staged files are gitignored and packed through the
|
|
21
|
+
sibling `.npmignore`.
|
|
22
|
+
- Once omowright#297 is released, its entry also opens with a `/*!` MIT banner that survives
|
|
23
|
+
bundling. Until then, and for every version, the staged `LICENSE` is the notice.
|
|
20
24
|
|
|
21
25
|
## BrowserSkill — driven, not vendored
|
|
22
26
|
|
|
@@ -75,14 +75,15 @@ you hit and ask.
|
|
|
75
75
|
|
|
76
76
|
```js
|
|
77
77
|
const session = await omowright.connectBrowserSkill({ name: "<task>", focused: false })
|
|
78
|
+
const sync = async () => (await session.cooperate("sync")).context_id // one context per page action
|
|
78
79
|
try {
|
|
79
|
-
await session.navigate("https://example.com/", { waitUntil: "load" })
|
|
80
|
-
const { tree, refs, css } = await omowright.bskSnapshot(session, { interactive: true }) // OmOWright tree + refs, no trace in the page
|
|
81
|
-
await session.click({ selector: css.e3 })
|
|
80
|
+
await session.navigate("https://example.com/", { waitUntil: "load", context: await sync() })
|
|
81
|
+
const { tree, refs, css } = await omowright.bskSnapshot(session, { interactive: true, context: await sync() }) // OmOWright tree + refs, no trace in the page
|
|
82
|
+
await session.click({ selector: css.e3 }, { context: await sync() }) // css[ref] is null inside shadow roots:
|
|
82
83
|
const vom = await session.observe({ maxTokens: 4000 }) // then read the daemon's own tree ...
|
|
83
|
-
await session.click("@e7")
|
|
84
|
-
await session.fill(css.e5, "hello")
|
|
85
|
-
await session.press("Enter")
|
|
84
|
+
await session.click("@e7", { context: await sync() }) // ... and click its @eN ref
|
|
85
|
+
await session.fill(css.e5, "hello", { context: await sync() })
|
|
86
|
+
await session.press("Enter", { context: await sync() })
|
|
86
87
|
await session.waitForNavigation({ waitUntil: "load" })
|
|
87
88
|
const shot = await session.screenshot() // { buffer, width, height, captureId }
|
|
88
89
|
} finally {
|
|
@@ -97,6 +98,20 @@ try {
|
|
|
97
98
|
4. **Borrow a user tab explicitly** (`tabList({ scope: "user" })`, `tabBorrow(id)`, `tabReturn(id)`).
|
|
98
99
|
Borrowing prompts the user; never invent tab ids and never repeat a denied borrow.
|
|
99
100
|
5. **Always `stop()` the session,** on success and on failure.
|
|
101
|
+
6. **Sync before every page action.** The person at the keyboard can work in the same tab, so
|
|
102
|
+
BrowserSkill 0.4 refuses an action (`permission_denied`, `data.reason: "cooperation_sync_required"`)
|
|
103
|
+
unless it carries `{ context }` from the latest `session.cooperate("sync")`. A context is good
|
|
104
|
+
for one action: sync, act with `{ context }`, sync again. Navigation, every input method,
|
|
105
|
+
`evaluate` (and so `bskSnapshot`), `tabClose`, `resize`, `emulate`, `observe({ probeHover })` and
|
|
106
|
+
`screenshot({ fullPage: true })` need it; plain reads (`observe`, `snapshot`, `getHtml`,
|
|
107
|
+
`screenshot()`, `console`, `network`, `waitForNavigation`) do not.
|
|
108
|
+
7. **On `cooperation_sync_required`, wait for the person, then replan.** Call
|
|
109
|
+
`session.cooperate("wait", { timeoutMs: 25_000 })` until it reports `ready`, read the page again
|
|
110
|
+
and decide afresh; never replay the refused action blindly.
|
|
111
|
+
8. **Pass only the options a method takes.** A gated action throws a `TypeError` on any other key
|
|
112
|
+
(a misspelt `contextId` would otherwise send no context). `bskSnapshot` and
|
|
113
|
+
`screenshot({ fullPage: true })` do not throw: they drop the stray key, and the daemon then
|
|
114
|
+
refuses the call with `cooperation_sync_required`.
|
|
100
115
|
|
|
101
116
|
Every method, its options, and the failure codes are in [references/commands.md](references/commands.md).
|
|
102
117
|
|
|
@@ -17,6 +17,38 @@ await session.stop() // ALWAYS, on success and failure
|
|
|
17
17
|
on purpose. Throws `BskRpcError` `no_browser_connected` when no extension is attached — that is a
|
|
18
18
|
stop, not a cue to launch something else.
|
|
19
19
|
|
|
20
|
+
## Shared control (BrowserSkill 0.4+)
|
|
21
|
+
|
|
22
|
+
The person at the keyboard can work in the task tab while you do, so the extension refuses every
|
|
23
|
+
gated page action with `permission_denied` / `data.reason: "cooperation_sync_required"` unless it
|
|
24
|
+
carries the `context_id` of the latest `session.cooperate("sync")`. The daemon never fills it in
|
|
25
|
+
for you.
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
const sync = async () => (await session.cooperate("sync")).context_id
|
|
29
|
+
await session.click("@e3", { context: await sync() }) // one context, one action
|
|
30
|
+
await session.fill("#q", "hello", { clearBefore: true, context: await sync() })
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
| Call | Use |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `session.cooperate("sync", { tabId, maxTokens })` | returns `{ context_id, ... }`; pass it as `{ context }` to the next gated action, then sync again |
|
|
36
|
+
| `session.cooperate("wait", { tabId, timeoutMs })` | after `cooperation_sync_required`: blocks (at most 25 s per call) until the person is done; repeat until it reports `ready`, then sync and replan from the live page |
|
|
37
|
+
|
|
38
|
+
- **Gated** (need `{ context }`): `navigate` (except the first navigation of the untouched blank tab),
|
|
39
|
+
`back`, `forward`, `reload`, `click`, `hover`, `focus`, `blur`, `fill`, `press`, `select`,
|
|
40
|
+
`scrollTo`, `wheel`, `evaluate` (and so `bskSnapshot`), `tabClose`, `resize`, `emulate`,
|
|
41
|
+
`observe({ probeHover: true })`, `screenshot({ fullPage: true })`.
|
|
42
|
+
- **Not gated:** `observe`, `snapshot`, `getHtml`, `screenshot()`, `console`, `network`,
|
|
43
|
+
`waitForNavigation`, the tab list/borrow/return calls, `requestHelp`.
|
|
44
|
+
- `dependsOn: ["@e2", ...]` narrows the check to the observed regions your decision used.
|
|
45
|
+
- A gated action accepts only its own options plus `{ context, dependsOn }`; any other key
|
|
46
|
+
(`contextId`, a stray option copied from another method) throws a `TypeError` before anything is
|
|
47
|
+
sent. Two exceptions: `bskSnapshot` and `screenshot({ fullPage: true })` pass unknown keys
|
|
48
|
+
through instead of throwing, so a misspelt `contextId` there sends no context and the daemon
|
|
49
|
+
refuses the call with `cooperation_sync_required`.
|
|
50
|
+
- Never replay a refused action blindly: the page may have changed under the person's hands.
|
|
51
|
+
|
|
20
52
|
## Targets
|
|
21
53
|
|
|
22
54
|
| Form | Meaning |
|
|
@@ -30,12 +62,12 @@ stop, not a cue to launch something else.
|
|
|
30
62
|
|
|
31
63
|
| Call | Returns |
|
|
32
64
|
|---|---|
|
|
33
|
-
| `bskSnapshot(session, { interactive, maxDepth })` | `{ tree, refs, css }` — the OmOWright accessibility tree with refs, computed in the page **without** leaving a global or touching the DOM |
|
|
65
|
+
| `bskSnapshot(session, { interactive, maxDepth, context })` | `{ tree, refs, css }` — the OmOWright accessibility tree with refs, computed in the page **without** leaving a global or touching the DOM |
|
|
34
66
|
| `session.observe({ maxTokens, cursor, probeHover })` | the daemon's semantic tree (`@vom`) with `@eN` refs, layers and hover probes — **the default read for shadow DOM and iframes** |
|
|
35
67
|
| `session.snapshot({ maxDepth, maxTokens })` | the daemon's plain accessibility tree |
|
|
36
68
|
| `session.getHtml({ ref, maxBytes })` | exact markup |
|
|
37
69
|
| `session.screenshot({ ref })` / `screenshot({ fullPage: true })` | `{ buffer, width, height, captureId }`; full-page captures stream back in chunks |
|
|
38
|
-
| `session.evaluate(expression, { awaitPromise, timeoutMs })` | `{ ok, value, error }` — **check `.ok`**; a resolved promise does not mean the script succeeded |
|
|
70
|
+
| `session.evaluate(expression, { awaitPromise, timeoutMs, context })` | `{ ok, value, error }` — **check `.ok`**; a resolved promise does not mean the script succeeded |
|
|
39
71
|
| `session.console({ since })` / `session.network({ since })` | buffered console entries / request metadata (no bodies) |
|
|
40
72
|
|
|
41
73
|
**Refs are reissued by every read.** Read a ref and act on it in the same cycle. A ref captured
|
|
@@ -44,6 +76,10 @@ neighbouring row.
|
|
|
44
76
|
|
|
45
77
|
## Acting
|
|
46
78
|
|
|
79
|
+
Every call here is gated: add `context` (from `cooperate("sync")`) to its options object, as in
|
|
80
|
+
`session.click(target, { context })`, `session.resize(width, height, { context })`,
|
|
81
|
+
`session.tabClose(id, { context })`.
|
|
82
|
+
|
|
47
83
|
| Need | Call |
|
|
48
84
|
|---|---|
|
|
49
85
|
| Click | `session.click(target, { button, clickCount, modifiers })` |
|
|
@@ -75,7 +111,7 @@ Traps:
|
|
|
75
111
|
const { tabs } = await session.tabList({ scope: "user" }) // "user" | "agent" | "all"
|
|
76
112
|
await session.tabBorrow(tabId) // the user confirms in the browser (60 s)
|
|
77
113
|
await session.tabReturn(tabId) // stop() returns anything still borrowed
|
|
78
|
-
await session.tabCreate({ url }); await session.tabSelect(id); await session.tabClose(id)
|
|
114
|
+
await session.tabCreate({ url }); await session.tabSelect(id); await session.tabClose(id, { context: await sync() })
|
|
79
115
|
```
|
|
80
116
|
|
|
81
117
|
Never invent tab ids and never repeat a denied borrow.
|
|
@@ -96,7 +132,8 @@ Every refusal is a `BskRpcError` with the daemon's own `code`:
|
|
|
96
132
|
| `no_browser_connected` | no extension attached | run the onboarding script, relay the human step, wait |
|
|
97
133
|
| `not_found` | stale ref or unknown session | read again; if the session is gone, start a new one |
|
|
98
134
|
| `invalid_params` | wrong option shape | fix the call, do not retry as-is |
|
|
99
|
-
| `permission_denied`
|
|
135
|
+
| `permission_denied` with `data.reason: "cooperation_sync_required"` | a gated action without the latest sync context, or the person is using the tab | `cooperate("wait")` until `ready`, sync, read the page again, replan |
|
|
136
|
+
| `permission_denied` (any other reason) | `evaluate` on a tab outside the Agent Window, or a denied borrow | stop; the user said no |
|
|
100
137
|
| `timeout` | the tool did not finish in its budget | read the page state before retrying once |
|
|
101
138
|
| `user_aborted` | the user pressed Stop in the browser | stop the task and report |
|
|
102
139
|
| `cdp_failed` | the page cannot be attached (restricted URL, DevTools open) | say which page and why |
|
package/packages/omo-codex/plugin/skills/browser/references/owned-engine/frames-and-humans.md
CHANGED
|
@@ -19,10 +19,21 @@ miss has another cause and you climb the ladder instead.
|
|
|
19
19
|
|
|
20
20
|
## Dialogs never block
|
|
21
21
|
|
|
22
|
-
`alert`, `confirm`, `prompt`, and `beforeunload` are answered
|
|
23
|
-
|
|
24
|
-
Default to accepting (`{ accept: true }`; a
|
|
25
|
-
`{
|
|
22
|
+
`alert`, `confirm`, `prompt`, and `beforeunload` are answered at the protocol layer, before the
|
|
23
|
+
page sees them: by a `dialog` listener that answers, otherwise by the `dialogPolicy` passed to
|
|
24
|
+
`connectPipe` (or `browser.setDialogPolicy`). Default to accepting (`{ accept: true }`; a policy
|
|
25
|
+
function receives a plain `{ type, message, defaultPrompt, url }` and returns `{ accept, promptText }`).
|
|
26
|
+
|
|
27
|
+
`page.on("dialog", (dialog) => ...)` hands each listener a Playwright-style `Dialog` object, not a
|
|
28
|
+
plain object: read it through methods (`dialog.type()`, `dialog.message()`, `dialog.defaultValue()`,
|
|
29
|
+
and the `dialog.url` getter). A listener can answer it itself, which replaces the policy for that
|
|
30
|
+
dialog; a listener that only observes leaves it to the policy:
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
page.on("dialog", (dialog) => dialog.type() === "prompt" ? dialog.accept("42") : dialog.dismiss())
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
A dialog is answered once; a second `accept()` / `dismiss()` throws. A run that hangs on
|
|
26
37
|
an unhandled dialog looks exactly like a hang with no cause, which is the most expensive kind to
|
|
27
38
|
diagnose.
|
|
28
39
|
|
|
@@ -28,13 +28,15 @@ await session.tabReturn(vault.tab_id)
|
|
|
28
28
|
|
|
29
29
|
The app mutates its URL hash without updating the document title, so a signed-in vault can still
|
|
30
30
|
report a sign-in title. A live session's `location.href` contains the app path and never the
|
|
31
|
-
sign-in path. Read the URL from `tabList`, or `session.evaluate("location.href")
|
|
31
|
+
sign-in path. Read the URL from `tabList`, or `session.evaluate("location.href", { context })` with a
|
|
32
|
+
fresh `context` from `session.cooperate("sync")` (see the shared-control section of
|
|
33
|
+
[../commands.md](../commands.md)).
|
|
32
34
|
|
|
33
35
|
## The browser may be shared
|
|
34
36
|
|
|
35
37
|
Other automation may be driving the same window.
|
|
36
38
|
|
|
37
|
-
- **Clear the search box before typing** (`fill(target, value, { clearBefore: true })`). It often
|
|
39
|
+
- **Clear the search box before typing** (`fill(target, value, { clearBefore: true, context })`). It often
|
|
38
40
|
holds someone else's query, and typing alone appends to it, returning confident results for the
|
|
39
41
|
wrong search.
|
|
40
42
|
- **Read the autocomplete listbox, not the results grid.** The grid holds whatever query was last
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yeongyu Kim
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "0.3.0",
|
|
3
|
-
"sourceDigest": "
|
|
3
|
+
"sourceDigest": "cbbe7740c45d92126187ac9a7e460a1ff5b4882b653547ec3aee5a11c64b6ccf",
|
|
4
4
|
"files": {
|
|
5
5
|
"index.js": "f026b391aead15d15f361e82861336c023c80c42b01fc0ba28f6d5d77a16acc8",
|
|
6
|
-
"page-bundle.js": "ca93c410e45469db3f22951d953e32444975daf8827ff10a877c537338c8feb0"
|
|
6
|
+
"page-bundle.js": "ca93c410e45469db3f22951d953e32444975daf8827ff10a877c537338c8feb0",
|
|
7
|
+
"LICENSE": "b083425948376611de9b92b0aeb7377e604505756ea427e541a34d9b030d4dc1"
|
|
7
8
|
},
|
|
8
|
-
"stagedAtUtc": "2026-11-
|
|
9
|
+
"stagedAtUtc": "2026-11-10T19:29:58.468Z"
|
|
9
10
|
}
|
|
@@ -62,10 +62,11 @@ When the bug only happens signed in:
|
|
|
62
62
|
|
|
63
63
|
```js
|
|
64
64
|
const session = await omowright.connectBrowserSkill({ name: "debug repro", focused: false })
|
|
65
|
+
const sync = async () => (await session.cooperate("sync")).context_id // BrowserSkill 0.4: one context per page action
|
|
65
66
|
try {
|
|
66
|
-
await session.navigate(url)
|
|
67
|
-
const { tree, css } = await omowright.bskSnapshot(session, { interactive: true })
|
|
68
|
-
await session.click({ selector: css.e7 })
|
|
67
|
+
await session.navigate(url, { context: await sync() })
|
|
68
|
+
const { tree, css } = await omowright.bskSnapshot(session, { interactive: true, context: await sync() })
|
|
69
|
+
await session.click({ selector: css.e7 }, { context: await sync() })
|
|
69
70
|
const errors = await session.console({ since: 0 })
|
|
70
71
|
const shot = await session.screenshot()
|
|
71
72
|
} finally {
|
|
@@ -111,7 +111,7 @@ The rest of the surface (CUA coordinates, captcha solving, routes, traces, frame
|
|
|
111
111
|
|
|
112
112
|
### Tier 2b — attached engine (the user's account on a blocked host)
|
|
113
113
|
|
|
114
|
-
When the blocked flow needs the user's account, drive the browser they are already signed into instead of cloning their profile: `connectBrowserSkill()` → `session.navigate` → `bskSnapshot(session)` / `session.observe()` → `session.click` → `session.stop()
|
|
114
|
+
When the blocked flow needs the user's account, drive the browser they are already signed into instead of cloning their profile: `connectBrowserSkill()` → `session.navigate` → `bskSnapshot(session)` / `session.observe()` → `session.click` → `session.stop()`, each page action carrying `{ context }` from a fresh `session.cooperate("sync")` (BrowserSkill 0.4 refuses it otherwise). NEVER launch against or clear cookies/cache/site data from the user's live profile, and never fall back to the owned engine for an authenticated criterion: if no extension is connected, run the `browser` skill's onboarding script and relay its one human step. The full loop is the `browser` skill.
|
|
115
115
|
|
|
116
116
|
### Cookie login (cross-platform)
|
|
117
117
|
|
|
@@ -31,7 +31,7 @@ For work likely to exceed one wait cycle, require the child to send `WORKING: <t
|
|
|
31
31
|
|
|
32
32
|
# ULW-RESEARCH — Maximum-Saturation Research
|
|
33
33
|
|
|
34
|
-
You are the research orchestrator. The user has explicitly ordered exhaustive research: fan parallel worker swarms out over every relevant source, chase every lead they surface until the leads run dry, prove
|
|
34
|
+
You are the research orchestrator. The user has explicitly ordered exhaustive research: fan parallel worker swarms out over every relevant source, chase every lead they surface until the leads run dry, prove every conclusion by probing a source, reading the file, or running a tool before asserting it, and deliver a synthesis in which every claim carries a citation or a proof. Exhaustive coverage is the assignment, not a risk to manage.
|
|
35
35
|
|
|
36
36
|
## Activation
|
|
37
37
|
|
|
@@ -53,7 +53,7 @@ The research is done when all of these hold:
|
|
|
53
53
|
|
|
54
54
|
- Every axis from Phase 0 was covered by at least one dedicated worker.
|
|
55
55
|
- Every EXPAND lead was investigated or explicitly closed as a duplicate or dead end, and convergence was reached under the Phase 2 rules.
|
|
56
|
-
-
|
|
56
|
+
- Data came first: every conclusion was proven by probing a source, reading the file, or running a tool before it was asserted, never by plausibility, recall, or the shape of the code; contested, undocumented, and performance-shaped claims were additionally proven or refuted by executed code.
|
|
57
57
|
- Every claim in the deliverable cites a source or a verification artifact.
|
|
58
58
|
- Every asserted claim is represented in the claim graph, tied to an intent-vs-reality diff when an expected truth exists, and backed by observation manifest entries from independent observation groups or a documented single-source exception; convergence or exception status is explicit.
|
|
59
59
|
- The deliverable lane and format were derived from the destination or asked through the empty-info interview without blocking collection, recorded in `brief.md` with `answered_by`, and the final materials match that record.
|
|
@@ -74,7 +74,7 @@ Saturation is not just more searching; it is a knowledge-production protocol. Th
|
|
|
74
74
|
- `verification-economics.md` — one row per proof decision. Required fields: claim, risk, error cost, verification cost/time, chosen verification path, defer/verify decision, outcome, and residual risk.
|
|
75
75
|
- `cause-disappearance.md` — one row per causal finding. Required fields: cause id, expected truth, previous observation, `last_seen`, disconfirming observation, replacement cause if any, current status, and whether the violation is no longer observed.
|
|
76
76
|
|
|
77
|
-
Observation candidates and claim candidates travel back from workers as message text. The orchestrator writes the instrumentation artifacts, links candidates into the intent diff and claim graph, and records where each observation entered the synthesis. A
|
|
77
|
+
Observation candidates and claim candidates travel back from workers as message text. **Every conclusion stands on an observation a tool produced** — a page read, a file read, a command run — recorded in `observation-manifest.md`: a claim candidate, a DEAD END, a convergence call, and your own judgment that a topic is settled alike. What you or a worker knows from memory is a LEAD to probe, never evidence. The orchestrator writes the instrumentation artifacts, links candidates into the intent diff and claim graph, and records where each observation entered the synthesis. A claim is not ready for final materials until its expected truth/reality diff is closed or marked unknown, its claim node exists, and its independent-observation convergence status is supported or explicitly excepted.
|
|
78
78
|
|
|
79
79
|
## Run the swarm as a cooperating team
|
|
80
80
|
|
|
@@ -107,15 +107,15 @@ Every research spawn message contains, in order:
|
|
|
107
107
|
2. The budget lift: "This is an explicit exhaustive-research assignment. Your default retrieval budget and stop-when-answered rules do not apply — run the full protocol below and report every lead."
|
|
108
108
|
3. Scope — the axis, the sources to hit, and what a complete answer contains.
|
|
109
109
|
4. The role protocol (Phase 1).
|
|
110
|
-
5. The reply tail. EXPAND markers, observation candidates, and claim candidates travel back as message text, never as files. Every worker ends the reply with:
|
|
110
|
+
5. The reply tail. EXPAND markers, observation candidates, and claim candidates travel back as message text, never as files. Each claim candidate carries `OBSERVED: <URL read | file:line | command and its output>`; a claim the worker only remembers goes into the tail as a LEAD. Every worker ends the reply with:
|
|
111
111
|
|
|
112
112
|
```
|
|
113
113
|
## EXPAND
|
|
114
114
|
- LEAD: <discovery not yet investigated> — WHY: <why it matters> — ANGLE: <suggested search>
|
|
115
|
-
- DEAD END: <lead explored to exhaustion>
|
|
115
|
+
- DEAD END: <lead explored to exhaustion> — PROBED: <the searches, reads, or commands that exhausted it>
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
A worker with nothing to expand writes `## EXPAND` followed by `none — <one-line reason>`. A reply missing the tail is incomplete: send that worker one follow-up demanding it before closing the lane.
|
|
118
|
+
A worker with nothing to expand writes `## EXPAND` followed by `none — <one-line reason>`. A reply missing the tail, or a claim or DEAD END missing its `OBSERVED:`/`PROBED:` line, is incomplete: send that worker one follow-up demanding it before closing the lane.
|
|
119
119
|
|
|
120
120
|
## Execution references
|
|
121
121
|
|
|
@@ -139,7 +139,7 @@ task(subagent_type="explore", run_in_background=true, prompt="TASK: act as a cod
|
|
|
139
139
|
This is an explicit exhaustive-research assignment. Your default retrieval budget and stop-when-answered rules do not apply — run the full protocol below and report every lead.
|
|
140
140
|
SCOPE: find everything in this codebase related to <angle>: <what complete looks like>.
|
|
141
141
|
PROTOCOL: grep 3+ keyword variations; structural search; LSP references; globs; git history (-S and --grep). Cross-validate across tools. Report absolute paths and file:line patterns.
|
|
142
|
-
End your reply with the ## EXPAND tail: '- LEAD: <discovery> — WHY: <why> — ANGLE: <search>' per lead, or 'none — <reason>'.")
|
|
142
|
+
Tag every claim OBSERVED: <URL | file:line | command>. End your reply with the ## EXPAND tail: '- LEAD: <discovery> — WHY: <why> — ANGLE: <search>' per lead, '- DEAD END: <lead> — PROBED: <what exhausted it>', or 'none — <reason>'.")
|
|
143
143
|
```
|
|
144
144
|
|
|
145
145
|
## Phase 2 — Expand until convergence
|
|
@@ -154,7 +154,7 @@ This loop is what makes the mode research rather than search. Collect returns as
|
|
|
154
154
|
task(category="deep-low", load_skills=["browser"], run_in_background=true, prompt="TASK: expansion wave <N> — investigate: <lead>.
|
|
155
155
|
PARENT: <which return surfaced it>. This is an explicit exhaustive-research assignment; budgets do not apply.
|
|
156
156
|
<role protocol for the lead's territory — web protocol for external leads, explore protocol for codebase leads>
|
|
157
|
-
End your reply with the ## EXPAND tail.")
|
|
157
|
+
Tag every claim OBSERVED: <URL | file:line | command>. End your reply with the ## EXPAND tail.")
|
|
158
158
|
```
|
|
159
159
|
|
|
160
160
|
### Excursions — dive deep on a new find, then surface back out
|
|
@@ -65,14 +65,15 @@ cloning its profile:
|
|
|
65
65
|
|
|
66
66
|
```js
|
|
67
67
|
const session = await omowright.connectBrowserSkill({ name: "visual-qa capture", focused: false })
|
|
68
|
+
const sync = async () => (await session.cooperate("sync")).context_id // BrowserSkill 0.4: one context per page action
|
|
68
69
|
try {
|
|
69
|
-
await session.navigate(url, { waitUntil: "load" })
|
|
70
|
-
await session.resize(1440, 900)
|
|
70
|
+
await session.navigate(url, { waitUntil: "load", context: await sync() })
|
|
71
|
+
await session.resize(1440, 900, { context: await sync() }) // desktop column of the matrix
|
|
71
72
|
await Bun.write(`${outDir}/${route}-1440-top.png`, (await session.screenshot()).buffer) // { buffer, width, height }
|
|
72
|
-
await session.emulate({ overrides: { width: 390, mobile: true } }) // phone column; `off: true` restores
|
|
73
|
+
await session.emulate({ overrides: { width: 390, mobile: true }, context: await sync() }) // phone column; `off: true` restores
|
|
73
74
|
await Bun.write(`${outDir}/${route}-390-top.png`, (await session.screenshot()).buffer)
|
|
74
75
|
} finally {
|
|
75
|
-
await session.emulate({ off: true })
|
|
76
|
+
await session.emulate({ off: true, context: await sync() })
|
|
76
77
|
await session.stop()
|
|
77
78
|
}
|
|
78
79
|
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// omo-codex-install:
|
|
2
|
+
// omo-codex-install:1b58911bb65b46e8c2406417c7e54aa609dc91891ae33c221e3eb29acf7f1e87:1a293c51c2cceebfc0900f7b2a1266e9fb736ff02a50710b66ab4628f75afdfe
|
|
3
3
|
var __esm = (fn, res, err) => () => {
|
|
4
4
|
if (fn)
|
|
5
5
|
try {
|
|
@@ -10205,7 +10205,7 @@ var package_default;
|
|
|
10205
10205
|
var init_package = __esm(() => {
|
|
10206
10206
|
package_default = {
|
|
10207
10207
|
name: "@oh-my-opencode/omo-codex",
|
|
10208
|
-
version: "5.1.
|
|
10208
|
+
version: "5.1.68",
|
|
10209
10209
|
type: "module",
|
|
10210
10210
|
private: true,
|
|
10211
10211
|
description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
|
|
@@ -13154,7 +13154,7 @@ var LATEST_MODEL_BY_FAMILY = {
|
|
|
13154
13154
|
claudeOpus: "claude-opus-5-5",
|
|
13155
13155
|
claudeSonnet: "claude-sonnet-5-5",
|
|
13156
13156
|
claudeHaiku: "claude-haiku-5-5",
|
|
13157
|
-
claudeFable: "claude-fable-5-
|
|
13157
|
+
claudeFable: "claude-fable-5-2",
|
|
13158
13158
|
gptAstra: "gpt-6-astra",
|
|
13159
13159
|
gptSol: "gpt-6.1-sol",
|
|
13160
13160
|
gptSolFast: "gpt-6.1-sol-fast",
|
|
@@ -7,16 +7,20 @@ plus a staged copy of one library it drives.
|
|
|
7
7
|
|
|
8
8
|
Both engines this skill documents are provided by **omowright**.
|
|
9
9
|
|
|
10
|
-
- Upstream: the `omowright`
|
|
11
|
-
|
|
10
|
+
- Upstream: the `omowright` package (npm, source on GitHub). The root `package.json` declares it
|
|
11
|
+
as a semver range (`^0.3.0` today); the exact version installed is recorded in `bun.lock` and in
|
|
12
|
+
the staged `manifest.json`.
|
|
12
13
|
- License: MIT
|
|
13
14
|
- What ships here: `runtime/omowright/index.js` (the library bundled into one ESM file, including
|
|
14
|
-
its `ws` and `zod` dependencies)
|
|
15
|
-
script it reads at import time)
|
|
15
|
+
its `ws` and `zod` dependencies), `runtime/omowright/page-bundle.js` (the in-page snapshot
|
|
16
|
+
script it reads at import time) and `runtime/omowright/LICENSE` (omowright's MIT text, copied
|
|
17
|
+
verbatim), staged at build time by
|
|
16
18
|
`packages/shared-skills/stage-omowright-runtime.mjs` from the pinned root devDependency, with a
|
|
17
|
-
`manifest.json` recording the version and file digests.
|
|
18
|
-
staged files are gitignored and packed through the
|
|
19
|
-
|
|
19
|
+
`manifest.json` recording the version and file digests. Staging fails when omowright has no
|
|
20
|
+
`LICENSE`. The repository holds no copy; the staged files are gitignored and packed through the
|
|
21
|
+
sibling `.npmignore`.
|
|
22
|
+
- Once omowright#297 is released, its entry also opens with a `/*!` MIT banner that survives
|
|
23
|
+
bundling. Until then, and for every version, the staged `LICENSE` is the notice.
|
|
20
24
|
|
|
21
25
|
## BrowserSkill — driven, not vendored
|
|
22
26
|
|
|
@@ -75,14 +75,15 @@ you hit and ask.
|
|
|
75
75
|
|
|
76
76
|
```js
|
|
77
77
|
const session = await omowright.connectBrowserSkill({ name: "<task>", focused: false })
|
|
78
|
+
const sync = async () => (await session.cooperate("sync")).context_id // one context per page action
|
|
78
79
|
try {
|
|
79
|
-
await session.navigate("https://example.com/", { waitUntil: "load" })
|
|
80
|
-
const { tree, refs, css } = await omowright.bskSnapshot(session, { interactive: true }) // OmOWright tree + refs, no trace in the page
|
|
81
|
-
await session.click({ selector: css.e3 })
|
|
80
|
+
await session.navigate("https://example.com/", { waitUntil: "load", context: await sync() })
|
|
81
|
+
const { tree, refs, css } = await omowright.bskSnapshot(session, { interactive: true, context: await sync() }) // OmOWright tree + refs, no trace in the page
|
|
82
|
+
await session.click({ selector: css.e3 }, { context: await sync() }) // css[ref] is null inside shadow roots:
|
|
82
83
|
const vom = await session.observe({ maxTokens: 4000 }) // then read the daemon's own tree ...
|
|
83
|
-
await session.click("@e7")
|
|
84
|
-
await session.fill(css.e5, "hello")
|
|
85
|
-
await session.press("Enter")
|
|
84
|
+
await session.click("@e7", { context: await sync() }) // ... and click its @eN ref
|
|
85
|
+
await session.fill(css.e5, "hello", { context: await sync() })
|
|
86
|
+
await session.press("Enter", { context: await sync() })
|
|
86
87
|
await session.waitForNavigation({ waitUntil: "load" })
|
|
87
88
|
const shot = await session.screenshot() // { buffer, width, height, captureId }
|
|
88
89
|
} finally {
|
|
@@ -97,6 +98,20 @@ try {
|
|
|
97
98
|
4. **Borrow a user tab explicitly** (`tabList({ scope: "user" })`, `tabBorrow(id)`, `tabReturn(id)`).
|
|
98
99
|
Borrowing prompts the user; never invent tab ids and never repeat a denied borrow.
|
|
99
100
|
5. **Always `stop()` the session,** on success and on failure.
|
|
101
|
+
6. **Sync before every page action.** The person at the keyboard can work in the same tab, so
|
|
102
|
+
BrowserSkill 0.4 refuses an action (`permission_denied`, `data.reason: "cooperation_sync_required"`)
|
|
103
|
+
unless it carries `{ context }` from the latest `session.cooperate("sync")`. A context is good
|
|
104
|
+
for one action: sync, act with `{ context }`, sync again. Navigation, every input method,
|
|
105
|
+
`evaluate` (and so `bskSnapshot`), `tabClose`, `resize`, `emulate`, `observe({ probeHover })` and
|
|
106
|
+
`screenshot({ fullPage: true })` need it; plain reads (`observe`, `snapshot`, `getHtml`,
|
|
107
|
+
`screenshot()`, `console`, `network`, `waitForNavigation`) do not.
|
|
108
|
+
7. **On `cooperation_sync_required`, wait for the person, then replan.** Call
|
|
109
|
+
`session.cooperate("wait", { timeoutMs: 25_000 })` until it reports `ready`, read the page again
|
|
110
|
+
and decide afresh; never replay the refused action blindly.
|
|
111
|
+
8. **Pass only the options a method takes.** A gated action throws a `TypeError` on any other key
|
|
112
|
+
(a misspelt `contextId` would otherwise send no context). `bskSnapshot` and
|
|
113
|
+
`screenshot({ fullPage: true })` do not throw: they drop the stray key, and the daemon then
|
|
114
|
+
refuses the call with `cooperation_sync_required`.
|
|
100
115
|
|
|
101
116
|
Every method, its options, and the failure codes are in [references/commands.md](references/commands.md).
|
|
102
117
|
|