explorbot 0.2.3 → 0.2.5
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/README.md +1 -1
- package/bin/explorbot-cli.ts +26 -8
- package/boat/api-tester/src/cli.ts +17 -0
- package/boat/api-tester/src/config.ts +4 -2
- package/boat/doc-collector/bin/doc-collector-cli.ts +2 -0
- package/boat/doc-collector/src/ai/documentarian.ts +61 -31
- package/boat/doc-collector/src/cli.ts +14 -1
- package/boat/doc-collector/src/config.ts +4 -2
- package/boat/prima/bin/prima-cli.ts +0 -0
- package/boat/prima/src/activity-line.ts +33 -0
- package/boat/prima/src/cli.ts +127 -86
- package/boat/prima/src/envelope.ts +102 -52
- package/boat/prima/src/prima.ts +567 -128
- package/boat/prima/src/pw-parser.ts +11 -1
- package/boat/prima/src/pw-registry.ts +4 -5
- package/boat/prima/src/session-log.ts +126 -0
- package/dist/bin/explorbot-cli.js +26 -8
- package/dist/boat/api-tester/bin/apibot-cli.js +2 -0
- package/dist/boat/api-tester/src/cli.js +17 -0
- package/dist/boat/api-tester/src/config.js +4 -2
- package/dist/boat/doc-collector/bin/doc-collector-cli.js +2 -0
- package/dist/boat/doc-collector/src/ai/documentarian.js +44 -19
- package/dist/boat/doc-collector/src/cli.js +14 -1
- package/dist/boat/doc-collector/src/config.js +4 -2
- package/dist/boat/prima/src/activity-line.js +30 -0
- package/dist/boat/prima/src/cli.js +109 -77
- package/dist/boat/prima/src/envelope.js +94 -44
- package/dist/boat/prima/src/prima.js +533 -119
- package/dist/boat/prima/src/pw-parser.js +13 -1
- package/dist/boat/prima/src/pw-registry.js +4 -5
- package/dist/boat/prima/src/session-log.js +108 -0
- package/dist/package.json +3 -2
- package/dist/rules/navigator/verification-actions.md +20 -0
- package/dist/src/action-result.d.ts +7 -0
- package/dist/src/action-result.js +4 -0
- package/dist/src/action.d.ts +2 -0
- package/dist/src/action.js +41 -2
- package/dist/src/ai/captain/web-mode.js +6 -3
- package/dist/src/ai/captain.js +2 -0
- package/dist/src/ai/navigator.d.ts +34 -0
- package/dist/src/ai/navigator.js +237 -181
- package/dist/src/ai/pilot.d.ts +7 -0
- package/dist/src/ai/pilot.js +90 -2
- package/dist/src/ai/provider.d.ts +2 -2
- package/dist/src/ai/provider.js +14 -23
- package/dist/src/ai/rerunner.js +2 -1
- package/dist/src/ai/researcher/cache.d.ts +2 -0
- package/dist/src/ai/researcher/cache.js +10 -2
- package/dist/src/ai/researcher.js +3 -2
- package/dist/src/ai/rules.js +17 -10
- package/dist/src/ai/session-analyst.js +2 -0
- package/dist/src/ai/task-agent.js +4 -1
- package/dist/src/ai/tester.d.ts +6 -3
- package/dist/src/ai/tester.js +50 -46
- package/dist/src/ai/tools.d.ts +14 -0
- package/dist/src/ai/tools.js +117 -37
- package/dist/src/commands/config-command.d.ts +51 -0
- package/dist/src/commands/config-command.js +117 -0
- package/dist/src/commands/index.js +2 -0
- package/dist/src/config.d.ts +9 -1
- package/dist/src/config.js +53 -4
- package/dist/src/execution-controller.d.ts +2 -0
- package/dist/src/execution-controller.js +6 -0
- package/dist/src/explorbot.d.ts +2 -1
- package/dist/src/explorbot.js +7 -2
- package/dist/src/explorer.js +2 -3
- package/dist/src/playwright-recorder.js +30 -0
- package/dist/src/remote.d.ts +55 -0
- package/dist/src/remote.js +235 -0
- package/dist/src/reporter.d.ts +1 -0
- package/dist/src/reporter.js +7 -1
- package/dist/src/state-manager.d.ts +2 -1
- package/dist/src/state-manager.js +3 -1
- package/dist/src/stats.d.ts +1 -0
- package/dist/src/stats.js +1 -0
- package/dist/src/test-plan.d.ts +3 -0
- package/dist/src/test-plan.js +26 -0
- package/dist/src/utils/aria.d.ts +2 -8
- package/dist/src/utils/aria.js +69 -40
- package/dist/src/utils/html.js +1 -0
- package/dist/src/utils/logger.d.ts +7 -1
- package/dist/src/utils/logger.js +32 -0
- package/dist/src/utils/page-readiness.js +18 -1
- package/dist/src/utils/url-matcher.js +3 -0
- package/dist/src/utils/web-element.d.ts +2 -0
- package/dist/src/utils/web-element.js +8 -0
- package/dist/src/utils/web-sandbox.d.ts +1 -1
- package/dist/src/utils/web-sandbox.js +2 -3
- package/docs/api-testing/basics.md +90 -0
- package/docs/api-testing/planning.md +57 -0
- package/docs/api-testing/running-tests.md +55 -0
- package/docs/assets/cloud-report.png +0 -0
- package/docs/assets/html-report.png +0 -0
- package/docs/assets/langfuse-trace.png +0 -0
- package/docs/assets/successful-explore-run.png +0 -0
- package/docs/basics/getting-started.md +140 -0
- package/docs/basics/prerequisites.md +63 -0
- package/docs/basics/providers.md +362 -0
- package/docs/basics/running.md +78 -0
- package/docs/contributing/ai-integration-tests.md +57 -0
- package/docs/contributing/contributing.md +90 -0
- package/docs/contributing/demo-videos.md +36 -0
- package/docs/contributing/npm-package.md +138 -0
- package/docs/contributing/observability.md +227 -0
- package/docs/contributing/regression-tests.md +103 -0
- package/docs/contributing/testing.md +95 -0
- package/docs/doc-collection/basics.md +128 -0
- package/docs/doc-collection/crawling.md +67 -0
- package/docs/doc-collection/interactive-mode.md +99 -0
- package/docs/index.json +87 -0
- package/docs/reference/commands.md +997 -0
- package/docs/reference/configuration.md +569 -0
- package/docs/reference/scripting.md +303 -0
- package/docs/reference/websocket.md +50 -0
- package/docs/superpowers/plans/2026-08-01-actor-boat.md +925 -0
- package/docs/superpowers/plans/2026-08-01-prima-boat.md +1120 -0
- package/docs/superpowers/reviews/2026-08-06-prima-vs-playwright-cli.md +268 -0
- package/docs/superpowers/specs/2026-08-01-actor-boat-design.md +204 -0
- package/docs/superpowers/specs/2026-08-01-prima-boat-design.md +242 -0
- package/docs/superpowers/specs/2026-08-03-global-config-design.md +138 -0
- package/docs/superpowers/specs/2026-08-07-prima-fixes-design.md +394 -0
- package/docs/superpowers/specs/2026-08-18-prima-false-verdicts.md +159 -0
- package/docs/web-testing/agents.md +158 -0
- package/docs/web-testing/automated-tests.md +134 -0
- package/docs/web-testing/basics.md +91 -0
- package/docs/web-testing/customization.md +131 -0
- package/docs/web-testing/hooks.md +238 -0
- package/docs/web-testing/page-interaction.md +84 -0
- package/docs/web-testing/planner.md +122 -0
- package/docs/web-testing/rerun.md +164 -0
- package/docs/web-testing/researcher.md +380 -0
- package/docs/workflow/agentic-usage.md +233 -0
- package/docs/workflow/application-spec.md +73 -0
- package/docs/workflow/ci.md +202 -0
- package/docs/workflow/knowledge.md +310 -0
- package/docs/workflow/planning-styles.md +67 -0
- package/docs/workflow/reporting.md +133 -0
- package/docs/workflow/test-plans.md +90 -0
- package/package.json +3 -2
- package/rules/navigator/verification-actions.md +20 -0
- package/src/action-result.ts +11 -0
- package/src/action.ts +43 -3
- package/src/ai/captain/web-mode.ts +6 -3
- package/src/ai/captain.ts +3 -0
- package/src/ai/navigator.ts +255 -186
- package/src/ai/pilot.ts +104 -2
- package/src/ai/provider.ts +14 -24
- package/src/ai/rerunner.ts +2 -1
- package/src/ai/researcher/cache.ts +12 -2
- package/src/ai/researcher.ts +3 -2
- package/src/ai/rules.ts +17 -10
- package/src/ai/session-analyst.ts +2 -0
- package/src/ai/task-agent.ts +3 -1
- package/src/ai/tester.ts +52 -45
- package/src/ai/tools.ts +136 -37
- package/src/commands/config-command.ts +146 -0
- package/src/commands/index.ts +2 -0
- package/src/config.ts +60 -5
- package/src/execution-controller.ts +8 -0
- package/src/explorbot.ts +7 -3
- package/src/explorer.ts +2 -2
- package/src/playwright-recorder.ts +23 -0
- package/src/remote.ts +244 -0
- package/src/reporter.ts +7 -1
- package/src/state-manager.ts +6 -2
- package/src/stats.ts +1 -0
- package/src/test-plan.ts +29 -0
- package/src/utils/aria.ts +65 -45
- package/src/utils/html.ts +1 -0
- package/src/utils/logger.ts +33 -2
- package/src/utils/page-readiness.ts +24 -1
- package/src/utils/url-matcher.ts +3 -0
- package/src/utils/web-element.ts +9 -0
- package/src/utils/web-sandbox.ts +3 -4
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# Prima boat vs playwright-cli — field review
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-06
|
|
4
|
+
**Target:** Testeiya Agent (`localhost:3050`) — sidebar Workflows section + Skill editor
|
|
5
|
+
**Setup:** global config (`~/.explorbot/config.js`), no project config
|
|
6
|
+
**Models:** `groq/openai/gpt-oss-20b` (model), `openrouter/gpt-5.6-luna` (vision + agentic)
|
|
7
|
+
**Comparator:** `@playwright/cli` 0.1.13
|
|
8
|
+
**Method:** drive the feature with prima, fall back to playwright-cli whenever prima stalled
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Verdict up front
|
|
13
|
+
|
|
14
|
+
Prima is not a replacement for playwright-cli today. It is a strong *complement*: two of its
|
|
15
|
+
commands (`verify`, `ask`) do work playwright-cli cannot do at all, and four defects stop it
|
|
16
|
+
from owning the driving loop. Recommended split as it stands:
|
|
17
|
+
|
|
18
|
+
- **playwright-cli** — attach, navigate, read page state, drive verified locators.
|
|
19
|
+
- **prima** — `verify` for assertions, `ask` for visual judgement, `--no-heal` for a failure
|
|
20
|
+
report you can retarget from.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## The feature under test — it works
|
|
25
|
+
|
|
26
|
+
Everything the sidebar Workflow and Skill editor promises checked out.
|
|
27
|
+
|
|
28
|
+
**Workflows section**
|
|
29
|
+
|
|
30
|
+
- The rail button opens a Workflows panel with five categories: Analysis & Planning,
|
|
31
|
+
Test Design & Management, Test Execution & Automation, Reporting/CI-CD & Quality Gates,
|
|
32
|
+
Metrics/Release & Analytics.
|
|
33
|
+
- Accordion is single-open; the first category is expanded by default and lists its four
|
|
34
|
+
prompts (Review requirements, Risk-based focus, Analyze PR requirements, Analyze PR diff).
|
|
35
|
+
- "Workflow overview" opens the diagram dialog. Vision check and my own screenshot agree:
|
|
36
|
+
a clean left-to-right five-stage pipeline, arrows between stages, nothing clipped or
|
|
37
|
+
overlapping.
|
|
38
|
+
|
|
39
|
+
**Skill editor**
|
|
40
|
+
|
|
41
|
+
- Skills popover lists 42 skills with category filter chips.
|
|
42
|
+
- Row actions menu offers "Change skill globally", "Edit for this project", "Disable".
|
|
43
|
+
- The editor opens with the skill markdown loaded, Save disabled.
|
|
44
|
+
- Typing flips the header to `● unsaved` and enables Save.
|
|
45
|
+
- "Close editor" discards: no file appeared under `~/.testeiya/skills/`, and the agent
|
|
46
|
+
repo's `git status` stayed clean.
|
|
47
|
+
|
|
48
|
+
One cosmetic thing worth a look: the filter chips include single-item categories named
|
|
49
|
+
after the skill itself — "Playwright Best Practices Skill 1", "Playwright Cli 1" — next to
|
|
50
|
+
real groupings like "Test Management 12". Category derivation looks like it falls back to
|
|
51
|
+
the skill name when a skill has no category.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Where prima was better
|
|
56
|
+
|
|
57
|
+
**1. `verify` — the standout.** One command turns a sentence into a pass/fail *and* the
|
|
58
|
+
assertion code that proved it.
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
prima verify "the sidebar Workflows section lists five workflow categories, and the
|
|
62
|
+
Analysis & Planning category is expanded showing individual workflow prompts"
|
|
63
|
+
→ 14.8s, passed: true
|
|
64
|
+
I.seeElement({"role":"button","text":"Analysis & Planning"});
|
|
65
|
+
... all five categories ...
|
|
66
|
+
I.see('Review requirements', '#base-ui-_r_2al_'); ... all four prompts ...
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
With playwright-cli the same check is snapshot → read the tree myself → write five
|
|
70
|
+
assertions by hand. Prima did it in one call, and the output is reusable test material.
|
|
71
|
+
This is the command that justifies the boat.
|
|
72
|
+
|
|
73
|
+
**2. `ask` — visual judgement with no image in my context.**
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
prima ask "Is the workflow diagram laid out as a readable left-to-right pipeline,
|
|
77
|
+
or is anything visually broken, overlapping or cut off?"
|
|
78
|
+
→ 8.7s, correct answer
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
I checked it against the PNG afterwards and it was right. playwright-cli can only hand me
|
|
82
|
+
a file; *I* have to look at it, and the image lands in my context permanently.
|
|
83
|
+
|
|
84
|
+
**3. Descriptions outlive refs.** playwright-cli refs (`e13`, `e26`, `e647`) are snapshot-scoped.
|
|
85
|
+
This app re-renders constantly, so every interaction meant re-snapshotting for fresh refs —
|
|
86
|
+
8k bytes each time. `prima click "the Workflows button in the left vertical sidebar rail"`
|
|
87
|
+
needs no prior read at all.
|
|
88
|
+
|
|
89
|
+
**4. Artifacts stay on disk.** Every envelope wrote `aria.yml` / `page.html` and cited absolute
|
|
90
|
+
paths. `page.html` was 376K and never entered my context. That is the design goal, delivered.
|
|
91
|
+
|
|
92
|
+
**5. The `--no-heal` failure envelope is exactly right.**
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
prima pw '({page}) => page.click("[data-test=nonexistent-thing]", {timeout:3000})' --no-heal
|
|
96
|
+
→ 8.6s, ok: false
|
|
97
|
+
error: page.click: Timeout 3000ms exceeded. Call log: waiting for locator(...)
|
|
98
|
+
### Current page (compact ARIA) ← enough to retarget, without the full tree
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Error plus a compact ARIA snapshot in one response is better than what playwright-cli gives
|
|
102
|
+
on a failed click, which is the error alone.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Where playwright-cli was better
|
|
107
|
+
|
|
108
|
+
**1. Speed — one to two orders of magnitude.** `snapshot` returned in **0.2–0.3s**. Prima's
|
|
109
|
+
cheapest command was 6.1s; the median was ~12s; `go` took **3m00s** and one owned-browser
|
|
110
|
+
`verify` took **2m32s**. Across ~17 prima commands I spent roughly ten minutes waiting.
|
|
111
|
+
|
|
112
|
+
**2. It does exactly what you asked — nothing else.** `prima do` given two instructions
|
|
113
|
+
("close the dialog", "open the Skills menu") performed both and then kept going: searched the
|
|
114
|
+
skill list for "playwright-cli" and inserted the skill, leaving `/playwright-cli` typed into a
|
|
115
|
+
live chat box. Two instructions in, four actions out, `ok: true`. Prima's `go` did the same
|
|
116
|
+
during recovery — it clicked "Workspace", "Show panel", pressed F5 and clicked "Cancel" while
|
|
117
|
+
merely trying to navigate. playwright-cli has never once done something I did not type.
|
|
118
|
+
|
|
119
|
+
**3. Attach just works.** playwright-cli opened and reattached to its own browser with no
|
|
120
|
+
ceremony. Prima could not attach at all without hand-patching a file (details below).
|
|
121
|
+
|
|
122
|
+
**4. `eval` reaches state prima cannot express.** The one assertion prima got wrong —
|
|
123
|
+
"is Save enabled now?" — was a one-liner for playwright-cli:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
$PW eval '() => [...document.querySelectorAll("button")].filter(b=>/Save/.test(b.textContent))
|
|
127
|
+
.map(b=>({t:b.textContent.trim(), disabled:b.disabled}))'
|
|
128
|
+
→ [{ "t": "saveSave", "disabled": false }]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
playwright-cli's snapshot also carries `[disabled]`, `[pressed]`, `[active]` inline. Prima's
|
|
132
|
+
UI map carries none of that.
|
|
133
|
+
|
|
134
|
+
**5. Honest failures.** playwright-cli never told me an action succeeded when it hadn't.
|
|
135
|
+
Prima did (see #1 below).
|
|
136
|
+
|
|
137
|
+
**6. `research` costs more context than a snapshot, not less.** The one `research` call
|
|
138
|
+
returned ~5k tokens of UI-map markdown — versus 8,110 bytes (~2k tokens) for a full
|
|
139
|
+
playwright-cli snapshot of the same page. Its locators were also worse: generated Base-UI ids
|
|
140
|
+
(`button#base-ui-_R_qcmpbmulb_`) and positional CSS chains
|
|
141
|
+
(`div:nth-of-type(1) > div > div:nth-of-type(1) > div`), neither of which survives a re-render.
|
|
142
|
+
Prima's own compact-ARIA failure block is the cheaper, better read.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Defects found in prima, worst first
|
|
147
|
+
|
|
148
|
+
**1. Heal converts a failed action into a different action and reports success.**
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
prima pw '({page}) => page.click("[data-test=nonexistent-thing]", {timeout:3000})'
|
|
152
|
+
→ ok: true
|
|
153
|
+
healed: true (recovered after 1 attempt)
|
|
154
|
+
used: // Click the "New agent" button
|
|
155
|
+
I.click({ role: "button", text: "New agent" });
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The requested element does not exist. Heal did not find another route to the same intent —
|
|
159
|
+
there was no such intent to reach. It picked an unrelated control, clicked it, and returned
|
|
160
|
+
`ok: true`. An orchestrator that trusts the envelope believes its own action landed. Heal
|
|
161
|
+
should only re-route toward the *same* target; when the target cannot be identified, the
|
|
162
|
+
correct answer is the `--no-heal` envelope.
|
|
163
|
+
|
|
164
|
+
**2. `verify` false-negatives with no diagnostic.**
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
prima verify "the Save button in the skill editor is now enabled because the skill
|
|
168
|
+
content has unsaved changes"
|
|
169
|
+
→ passed: false
|
|
170
|
+
evidence: no assertion held on the current page
|
|
171
|
+
code: (empty)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The app was working — `● unsaved` was displayed and Save was enabled.
|
|
175
|
+
|
|
176
|
+
The cause is the vocabulary, not the model. `rules/navigator/verification-actions.md` offers
|
|
177
|
+
exactly nine assertions — `see`, `seeElement`, `seeInField`, `seeInTitle`, `seeInSource` and
|
|
178
|
+
their `dontSee*` counterparts — none of which express enabled/disabled/checked/selected, and
|
|
179
|
+
the rules additionally steer away from attribute selectors (`NEVER use ':has-text(...)'`,
|
|
180
|
+
"never check value via CSS attribute selectors"). So a claim about interactive state is
|
|
181
|
+
unprovable by construction, and prima reports that as the *feature* failing rather than as a
|
|
182
|
+
check it could not express. Empty `code:` and a generic evidence line leave no way to tell
|
|
183
|
+
"the app is broken" from "I could not phrase this".
|
|
184
|
+
|
|
185
|
+
**3. Auto-discovery of a playwright-cli session cannot work; `--endpoint` needs playwright 1.62.**
|
|
186
|
+
|
|
187
|
+
> **Corrected 2026-08-07 after re-testing.** The original run was on explorbot's pinned
|
|
188
|
+
> playwright **1.60.0** against a 1.61.0-alpha daemon, and concluded attach was broken
|
|
189
|
+
> outright. That was a stale-dependency artifact. Re-tested with `playwright@1.62.1` and
|
|
190
|
+
> `@playwright/cli@0.1.17` (playwright 1.62.0-alpha): `chromium.connect()` succeeds with
|
|
191
|
+
> **our own** playwright, and `prima verify --endpoint <sock>` returns `ok: true` in 16.6s.
|
|
192
|
+
> Upgrading the pin fixes the connect half. What remains is discovery.
|
|
193
|
+
|
|
194
|
+
- **Version skew (fixed by upgrading).** `playwright@^1.60` could not `connect()` to a
|
|
195
|
+
1.61/1.62 browser server — it timed out. `playwright@1.62.1` connects to both its own
|
|
196
|
+
minor and the 1.62.0-alpha daemon. The pin should move to `^1.62`.
|
|
197
|
+
- **Missing `workspaceDir` (still broken).** No `@playwright/cli` release writes a
|
|
198
|
+
`workspaceDir` field into `~/.cache/ms-playwright/b/browser@<guid>` — verified on 0.1.13
|
|
199
|
+
and 0.1.17. `parseDescriptor` (`boat/prima/src/pw-registry.ts:56`) requires it, so every
|
|
200
|
+
descriptor is dropped, `selectDescriptor` filters on a field that never exists, and
|
|
201
|
+
auto-discovery finds nothing no matter what version is installed. Prima cannot attach
|
|
202
|
+
without `--endpoint` unless it stops keying on `workspaceDir`.
|
|
203
|
+
- **The failure message sends you in a circle.** With a session open, discovery fails with
|
|
204
|
+
"No browser to drive... Open one first: `playwright-cli open <url>`" — advising exactly
|
|
205
|
+
what the user already did. `prima browser list` likewise reports "no browser instances
|
|
206
|
+
running" while a session is live.
|
|
207
|
+
|
|
208
|
+
**4. A redirect that appends query params is treated as failed navigation.** The app sends
|
|
209
|
+
`/` → `/?session=<uuid>&ws=1`. `prima go http://localhost:3050` burned **3 minutes** and eight
|
|
210
|
+
attempts before healing; against prima's own browser the same navigation ended in a hard tool
|
|
211
|
+
error after **2m32s** —
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
error: tool: Navigation to / failed: redirected to /?session=...&ws=1 and could not resolve
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
— in an envelope whose own inlined ARIA proves the page had loaded correctly. Session-param
|
|
218
|
+
redirects are common enough that this alone blocks unattended use.
|
|
219
|
+
|
|
220
|
+
### Smaller issues
|
|
221
|
+
|
|
222
|
+
- **`used:` is often not runnable.** `click` concatenated all five ladder attempts, including
|
|
223
|
+
invalid JS: `I.click(".sidebar button:has-text("Workflows")")`. `do` emitted a
|
|
224
|
+
`// 1. Open dialog...` comment line inside the code. The spec promises "the exact code that
|
|
225
|
+
worked" — it should be the winning line only.
|
|
226
|
+
- **`### Changes` / ariaDiff never appeared** in any successful envelope. That block is the
|
|
227
|
+
envelope's core evidence promise; without it, a successful `click` proves nothing and I had
|
|
228
|
+
to spend a playwright-cli snapshot to confirm every action.
|
|
229
|
+
- **`network.jsonl` is advertised in every envelope and was 0 bytes in all 18 runs.**
|
|
230
|
+
- **`click` reports itself as `do`.** Every `click` envelope printed `command: do "..."`.
|
|
231
|
+
- **Every command requires a URL** even when attached to a browser already sitting on the page,
|
|
232
|
+
and even when the site is registered. `EXPLORBOT_URL` satisfies config loading but not page
|
|
233
|
+
opening on an empty owned browser, which needs `--url` as well.
|
|
234
|
+
- **Prima pollutes a shared browser.** After `research`, the visual-annotation overlays
|
|
235
|
+
(`Legend`, `e8`, `e10`, …) were still in the live DOM and showed up in the next
|
|
236
|
+
playwright-cli snapshot.
|
|
237
|
+
|
|
238
|
+
### Environment friction (not prima's design)
|
|
239
|
+
|
|
240
|
+
- **`node_modules` is a committed, self-referential symlink.** `git ls-files -s node_modules`
|
|
241
|
+
shows mode `120000` pointing at `/home/davert/projects/explorbot/node_modules` — itself.
|
|
242
|
+
It was added in `7cc52eb` ("Let EXPLORBOT_* variables win over the global config"). Being
|
|
243
|
+
tracked, it overrides the `node_modules/` line in `.gitignore`. Every Node resolution fails
|
|
244
|
+
with `ELOOP` / "Too many levels of symbolic links", so `npx tsc`, the build, and the CLI are
|
|
245
|
+
all dead on a fresh checkout of this branch. Removing it and running `bun install` fixes it.
|
|
246
|
+
- `bun run build:npm` fails with `env: unknown error: execvp failed`; `bash scripts/build-npm.sh`
|
|
247
|
+
works.
|
|
248
|
+
- The `prima` bin is not exposed by the existing global npm link — `explorbot prima ...` only.
|
|
249
|
+
- Prima needs the Node build for browser-server endpoints, so `dist/` must exist before any of
|
|
250
|
+
this runs.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## What would make prima a replacement
|
|
255
|
+
|
|
256
|
+
In priority order:
|
|
257
|
+
|
|
258
|
+
1. Heal must never substitute a different target; unresolvable intent → failure envelope.
|
|
259
|
+
2. `verify` must distinguish "assertion failed" from "cannot express this assertion", and
|
|
260
|
+
`rules/navigator/verification-actions.md` needs state assertions
|
|
261
|
+
(enabled/disabled/checked/selected) alongside the nine text/presence ones it has now.
|
|
262
|
+
3. Treat a redirect that preserves origin and path as navigation success.
|
|
263
|
+
4. Move the playwright pin to `^1.62` (fixes `--endpoint`), and stop keying discovery on
|
|
264
|
+
`workspaceDir` — no `@playwright/cli` release emits it.
|
|
265
|
+
5. Emit `### Changes` on every action, and reduce `used:` to the winning line.
|
|
266
|
+
|
|
267
|
+
With 1–3 fixed, prima could own the assertion and inspection half of a session outright.
|
|
268
|
+
Driving would still belong to playwright-cli until the per-command latency comes down.
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Actor Boat — High-Level Browser Driver for Orchestrating Agents
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-01
|
|
4
|
+
**Status:** Draft for review
|
|
5
|
+
**Implementation model:** Opus
|
|
6
|
+
|
|
7
|
+
## Problem
|
|
8
|
+
|
|
9
|
+
Coding agents (Claude Code on Opus/Fable) drive browsers through playwright-cli or Playwright MCP. Every action forces page state (aria snapshots) into the orchestrator's context: the expensive model pays to read the tree, pick a ref, and re-read after every step, and each snapshot stays in conversation history compounding cost for the rest of the session. A 20-step flow means 20+ expensive perception roundtrips.
|
|
10
|
+
|
|
11
|
+
Explorbot already owns the layers that fix this: cheap-model perception (Navigator, Researcher), semantic diffs (ariaDiff, pageDiff), state tracking, and experience replay. The Actor boat exposes those layers as an intent-level CLI so the orchestrator sends instructions and receives compact evidence — page data never enters the expensive context on the happy path.
|
|
12
|
+
|
|
13
|
+
## Goals
|
|
14
|
+
|
|
15
|
+
- Orchestrator issues precise Playwright calls or natural-language instructions; explorbot's cheap models run the perception–action micro-loop.
|
|
16
|
+
- Every response is a uniform envelope: evidence of what happened, never a raw page dump.
|
|
17
|
+
- Failures exhaust cheap healing first, then return a compacted investigation so the orchestrator can drop down a level and drive directly.
|
|
18
|
+
- Zero project setup: works from any directory via env vars and a global user config, with per-host persistent state.
|
|
19
|
+
- Every successful action reports the exact code that worked, so sessions double as verified-locator material for test generation.
|
|
20
|
+
|
|
21
|
+
## Non-Goals
|
|
22
|
+
|
|
23
|
+
- Not a replacement for playwright-cli as a general browser tool.
|
|
24
|
+
- No MCP server, no SKILL.md package in v1 — the contract is taught entirely by `--help` text.
|
|
25
|
+
- No new core agents unless heal orchestration proves to need one (then it lives inside the boat).
|
|
26
|
+
|
|
27
|
+
## Architecture
|
|
28
|
+
|
|
29
|
+
A boat, following the existing `boat/api-tester` / `boat/doc-collector` pattern:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
boat/actor/
|
|
33
|
+
├── package.json # name: "actbot", own bin
|
|
34
|
+
├── bin/actbot-cli.ts # standalone CLI
|
|
35
|
+
└── src/
|
|
36
|
+
├── cli.ts # createActCommands('act') → composed into main CLI
|
|
37
|
+
├── actor.ts # Actor class wrapping ExplorBot (like DocBot)
|
|
38
|
+
├── envelope.ts # result envelope: inline render + artifact files
|
|
39
|
+
└── config.ts
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Registered in `bin/explorbot-cli.ts` via `program.addCommand(createActCommands('act'))`. The `Actor` class wraps `ExplorBot`, reusing `agentNavigator()`, `agentResearcher()`, `stateManager()`, Historian, and the Explorer/Action capture pipeline. Business logic lives in the Actor class and agents; CLI handlers stay thin, per repo convention.
|
|
43
|
+
|
|
44
|
+
## Command Surface
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
explorbot act pw "({ page }) => page.click('text=Login')" # raw Playwright fn, healed on failure
|
|
48
|
+
explorbot act do "click the login link" # NL action via Navigator
|
|
49
|
+
explorbot act click "Login" # targeted click via existing fallback ladder
|
|
50
|
+
explorbot act fill "Search" "wireless mouse" # targeted fill via existing ladder
|
|
51
|
+
explorbot act ask "what do I see here?" # cheap-model page Q&A via Researcher
|
|
52
|
+
explorbot act research [--data] [--deep] [--fresh] # verified UI map for precise pw driving
|
|
53
|
+
explorbot act verify "user is logged in" # AI assertion (alias: assert)
|
|
54
|
+
explorbot act go "billing settings" # URL or NL navigation
|
|
55
|
+
explorbot act browser start|stop|status|list # instance management (stop --all)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Tiering: `pw` = precise (no AI on happy path), `click`/`fill` = targeted with deterministic fallback ladders (AI only on ambiguity), `do` = intent (cheap-model planning). `select`, `pressKey`, `hover`, `drag` intentionally stay behind `pw` — a subcommand without a ladder is surface without value.
|
|
59
|
+
|
|
60
|
+
### Common flags
|
|
61
|
+
|
|
62
|
+
- `--instance <name>` / `-i` — which named browser daemon to talk to. Default instance otherwise.
|
|
63
|
+
- `--session [file]` — existing auth-session semantics; an autostarted instance launches with the saved cookies/storage state.
|
|
64
|
+
- `--no-heal` — fail fast without cheap-model recovery.
|
|
65
|
+
- `--ephemeral` — throwaway temp state dir instead of the per-host persistent one.
|
|
66
|
+
- `--framework playwright|codeceptjs` — output dialect for `used:` code (default from `ai.agents.historian.framework`).
|
|
67
|
+
- `--vision` — force screenshot pass for `ask`.
|
|
68
|
+
|
|
69
|
+
### Execution paths
|
|
70
|
+
|
|
71
|
+
- **pw**: the argument is a function expression in the exact shape `I.usePlaywrightTo` accepts — `({ page, browserContext, browser }) => ...` — checked only for being a parseable function, then interpolated directly into `I.usePlaywrightTo('pw', <fn>)` and executed through the Explorer/Action pipeline so state capture, ariaDiff, and experience recording come for free. Destructure whichever Playwright objects the call needs. Deterministic and near-instant on the happy path.
|
|
72
|
+
- **do**: one bounded Navigator invocation (max ~3 tool roundtrips) reusing the existing click/type/form tool ladders. Deterministic fast path first: if the instruction resolves to exactly one interactive ARIA node by role+name, execute with zero AI calls.
|
|
73
|
+
- **click / fill**: the existing multi-fallback ladders directly (text → ARIA → experience candidates); cheap-model disambiguation only when multiple candidates match.
|
|
74
|
+
- **ask**: Researcher answers from current compact ARIA / cached UI map; `--vision` routes through the vision model. Non-mutating.
|
|
75
|
+
- **research**: `researcher.research(state, { screenshot: true, data, deep, force })`. The envelope's `### Research` section carries the UI map inline — it is the deliverable: verified, live-tested locators that let the orchestrator drive `pw` precisely without reading raw ARIA. `--data` adds extracted data sections, `--deep` deep analysis, `--fresh` bypasses the cache; cached results keep the existing staleness banner. Non-mutating.
|
|
76
|
+
- **verify / assert**: `navigator.verifyState()` on the cheap model; verdict plus the assertion code that proved it.
|
|
77
|
+
- **go**: URL-shaped input navigates directly; intent-shaped input uses Navigator's stateful navigation with visited-state history and knowledge. Autostarts the instance like every other command.
|
|
78
|
+
|
|
79
|
+
### Examples of `do`
|
|
80
|
+
|
|
81
|
+
- `act do "click the login link"` → ARIA has one `link "Login"` → `I.click('Login')`, zero AI.
|
|
82
|
+
- `act do "search for 'wireless mouse'"` → cheap model plans fill + Enter → both lines reported in `used:`.
|
|
83
|
+
- `act do "dismiss the cookie banner"` → ambiguous → cheap model picks `button "Accept all"` from compact ARIA.
|
|
84
|
+
- `act do "open the newest invoice"` → list interpretation → cheap model over the UI map picks the first row link.
|
|
85
|
+
|
|
86
|
+
## The Envelope
|
|
87
|
+
|
|
88
|
+
The uniform response contract: every command prints the same block structure in the same order to stdout, success or failure. Two jobs: evidence (prove what happened without showing the page) and housekeeping (what is open, what to clean up, where to dig deeper).
|
|
89
|
+
|
|
90
|
+
### Success (~200–400 tokens inline)
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
### Result
|
|
94
|
+
ok: true
|
|
95
|
+
command: pw ({ page }) => page.click('text=Login')
|
|
96
|
+
healed: false
|
|
97
|
+
used: I.click('Login')
|
|
98
|
+
|
|
99
|
+
### Page
|
|
100
|
+
url: https://app.example.com/dashboard (changed: /login → /dashboard)
|
|
101
|
+
title: Dashboard
|
|
102
|
+
state: dashboard_h1_dashboard (new state, visit #1)
|
|
103
|
+
|
|
104
|
+
### Changes
|
|
105
|
+
ariaDiff:
|
|
106
|
+
added:
|
|
107
|
+
- heading "Dashboard"
|
|
108
|
+
- button "New Project"
|
|
109
|
+
removed:
|
|
110
|
+
- textbox "Email"
|
|
111
|
+
|
|
112
|
+
### Instance
|
|
113
|
+
instance: default (3 tabs) | other instances: auth-test (1 tab)
|
|
114
|
+
browser: running (started 12m ago)
|
|
115
|
+
|
|
116
|
+
### Artifacts
|
|
117
|
+
aria: <abs path>/output/act/<ts>/aria.yml
|
|
118
|
+
html: <abs path>/output/act/<ts>/page.html
|
|
119
|
+
network: <abs path>/output/act/<ts>/network.jsonl
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- `used:` — the exact code that worked (healed form when healed), rendered in the configured framework via Historian's converters. Sessions thereby double as a verified-locator oracle for test generation.
|
|
123
|
+
- `### Changes` becomes `### Answer` for `ask`, `### Verdict` (pass/fail + evidence line + assertion code) for `verify`, and `### Research` (the UI map, inline) for `research`.
|
|
124
|
+
- `### Instance` appears on every response — tab counts and other live instances — so the orchestrator sees leftover state and knows to close it when finished.
|
|
125
|
+
- Artifact paths are always absolute; full HTML, full ARIA, and the network log are always written, never inlined.
|
|
126
|
+
|
|
127
|
+
### Failure (after healing exhausted, ~1–2k tokens inline)
|
|
128
|
+
|
|
129
|
+
Same sections, plus:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
### Failure
|
|
133
|
+
error: locator 'text=Login' not found (timeout 5s)
|
|
134
|
+
|
|
135
|
+
### Healing attempts (3)
|
|
136
|
+
1. I.click('Login') → not visible
|
|
137
|
+
2. scroll + retry → covered by cookie banner
|
|
138
|
+
3. click 'Accept cookies', retry → navigation timeout
|
|
139
|
+
reasoning (compacted): ~5-line cheap-model summary of what it observed and why each attempt was chosen
|
|
140
|
+
|
|
141
|
+
### Current page (compact ARIA, inline)
|
|
142
|
+
- button "Accept cookies"
|
|
143
|
+
- link "Login"
|
|
144
|
+
...
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Inline: ariaDiff, error, compact ARIA. On disk: full HTML, full ARIA, network log. The orchestrator investigates from the inline compact ARIA and reads artifact files only when it needs depth.
|
|
148
|
+
|
|
149
|
+
## Heal Loop
|
|
150
|
+
|
|
151
|
+
On `pw`, `do`, `click`, or `fill` failure, the failing intent goes to Navigator's existing recovery ladder on the cheap model: alternative locators from ARIA/experience, scroll-into-view, overlay dismissal, retry. Capped at 3 attempts by default; `--no-heal` disables. Every attempt logs `{action, code, result, ariaDiff}`; reasoning is compacted to ~5 lines at the end. Heal success returns a success envelope with `healed: true` and writes the fix to experience so the next run replays it without AI. Heal exhaustion returns the failure envelope.
|
|
152
|
+
|
|
153
|
+
Tool errors (daemon unreachable, AI provider missing, invalid `pw` expression) are reported as `ok: false` with a `### Failure` naming the failed layer — never disguised as page failures.
|
|
154
|
+
|
|
155
|
+
## Instances & Sessions
|
|
156
|
+
|
|
157
|
+
- Named browser daemons via `--instance`; state persists across CLI invocations through the existing `explorbot browser start` server and `.browser-endpoint` discovery.
|
|
158
|
+
- Any `act` command with no running daemon autostarts one for its instance; combined with `--session [file]`, the autostarted browser launches already authenticated.
|
|
159
|
+
- `act browser start|stop|status|list` manages instances explicitly; `stop --all` kills everything.
|
|
160
|
+
|
|
161
|
+
## Config-Free Operation
|
|
162
|
+
|
|
163
|
+
Resolution ladder, first hit wins per setting:
|
|
164
|
+
|
|
165
|
+
1. Project config — `explorbot.config.js|ts` in cwd.
|
|
166
|
+
2. Global user config — `~/.config/explorbot/config.js|ts` (models, providers, keys).
|
|
167
|
+
3. Env vars — existing `EXPLORBOT_*` set, from process env, cwd `.env`, or `~/.config/explorbot/.env`.
|
|
168
|
+
|
|
169
|
+
The ladder lives in core config loading (`buildEnvConfig` grows global-config and global-`.env` sources); the boat inherits it.
|
|
170
|
+
|
|
171
|
+
With no project config, working dirs move to a persistent per-host state dir:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
~/.local/state/explorbot/<host>/
|
|
175
|
+
├── experience/
|
|
176
|
+
├── knowledge/
|
|
177
|
+
└── output/act/...
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Experience accumulates per target host across runs from any directory — zero-setup feel with memory. `--ephemeral` opts into a throwaway temp dir (CI, demos).
|
|
181
|
+
|
|
182
|
+
## Discovery
|
|
183
|
+
|
|
184
|
+
`explorbot act --help` (and `actbot --help`) is the sole teaching surface: it must compactly document the envelope shape, heal semantics, tiering (`pw` vs `click`/`fill` vs `do`), instance/session flags, and the artifact-file pattern. Clean stdout throughout (no banner).
|
|
185
|
+
|
|
186
|
+
## Testing
|
|
187
|
+
|
|
188
|
+
- Unit: envelope rendering (success, failure, ask/verify variants), `pw` expression validation, config ladder resolution.
|
|
189
|
+
- Integration: heal-loop prompts via the existing `@copilotkit/aimock` harness per `docs/contributing/ai-integration-tests.md`; fictional fixture data only.
|
|
190
|
+
- End-to-end smoke against a local fixture page: `pw` success, healed failure, exhausted failure, `do` fast path (zero AI), instance autostart with `--session`.
|
|
191
|
+
|
|
192
|
+
## Decisions Log
|
|
193
|
+
|
|
194
|
+
- Heal-first on all action failures (not fail-fast, not opt-in). `--no-heal` escape hatch.
|
|
195
|
+
- Failure delivery: ariaDiff + error + compact ARIA inline; full HTML/ARIA/network as files.
|
|
196
|
+
- Full command surface in v1 (pw, do, click, fill, ask, verify/assert, go, browser mgmt).
|
|
197
|
+
- Discovery via `--help` only; no SKILL.md or MCP in v1.
|
|
198
|
+
- Boat architecture (`boat/actor`, namespace `act`), not core commands.
|
|
199
|
+
- `--instance` for daemon switching; `--session` keeps existing auth-state meaning.
|
|
200
|
+
- Persistent per-host state dir by default in config-free mode; `--ephemeral` for temp.
|
|
201
|
+
- `used:` code in envelope via Historian converters; `verify` exposes assertion code.
|
|
202
|
+
- click/fill exposed as ladder-backed sugar; select/pressKey/hover/drag stay behind `pw`.
|
|
203
|
+
- `research` exposed with `--data`/`--deep`/`--fresh`; UI map inline as the deliverable (verified locators enable precise `pw` driving).
|
|
204
|
+
- Implementation runs on Opus.
|