scenescout 1.0.0 โ†’ 1.1.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # scenescout
2
2
 
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d3ebd73: Snapshots now list images that failed to load, under `BROKEN IMAGES`, read from the DOM. This catches an image whose URL answers 200 with something that is not an image, which the HTTP oracle cannot see because no request failed. Images that occupy no space (inside a closed panel, tracking pixels) are not reported.
8
+
9
+ An `<img>` is now named by its alt text and listed with the role `image`; it previously appeared as `generic "(unnamed)"`. For the uncommon `<img>` that is collected without a `data-testid` (one with `onclick` or an explicit role), this changes its element key, so states containing it are seen as new once.
10
+ - 5706a55: `scout_scan` now reads routes from source for React Router, Vue Router and Angular projects, including nested children, `<Route>` elements and Angular `loadChildren` files. These projects previously started with an empty route list and relied on link discovery alone, so a page nothing linked to was outside the completion contract. The reader is static and skips anything it cannot resolve: computed paths, spreads, identifiers, and relative paths whose parent is unknown.
11
+ - 6b6b786: The geometry oracle now reports a pinned control that sits underneath other pinned chrome, for example a sticky Save row covered by a fixed bar. Box overlap cannot tell which of two pinned elements is on top, so that pair was skipped; the new check hit-tests the control's centre in the page. It stays quiet for controls inside a scrollable pane, for dialogs, and for overlays covering half the viewport.
12
+ - 0d320b1: New write mode `observe` (`--observe`): nothing but `GET`, `HEAD` and `OPTIONS` requests leaves the page, except logging in, logging out and refreshing a token. Signing up and password changes are blocked. WebSocket frames are not inspected, and the engine says so when the app opens one. `read-only` lets an ordinary form `POST` through, which on a target holding real data creates a record. The skill now attaches in `observe` for a remote URL with no source unless told that form submissions are acceptable. Forms that could not be submitted stay in the gap ledger, worded as the mode's doing.
13
+
14
+ ### Patch Changes
15
+
16
+ - 0d320b1: The login exemption in the write policy no longer applies to destructive-looking requests in any mode. A path that merely contained a word such as `session` or `auth` previously carried a request like `POST /api/session/123/delete` through `read-only`. A form navigation blocked by the write policy is now reported as blocked; it was reported as an off-origin navigation, and the follow-up note blamed the app for discarding data.
17
+ - 4107696: `scenescout doctor` now suggests `npx -y scenescout install` when the tool was installed from npm. It previously suggested `npm run setup`, which exists only in a source checkout.
18
+
3
19
  ## 1.0.0
4
20
 
5
21
  ### Major Changes
package/README.md CHANGED
@@ -5,6 +5,7 @@
5
5
  **Exploratory UI testing, driven by an AI agent.**
6
6
 
7
7
  [![test](https://github.com/brunoboto96/SceneScout/actions/workflows/test.yml/badge.svg)](https://github.com/brunoboto96/SceneScout/actions/workflows/test.yml)
8
+ [![npm](https://img.shields.io/npm/v/scenescout.svg)](https://www.npmjs.com/package/scenescout)
8
9
  [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
10
  ![node >= 20](https://img.shields.io/badge/node-%E2%89%A5%2020-339933?logo=node.js&logoColor=white)
10
11
  ![MCP server](https://img.shields.io/badge/MCP-server-8A2BE2)
@@ -28,9 +29,11 @@ Scripted E2E suites answer one question โ€” *"does this exact flow still work?"*
28
29
 
29
30
  ## ๐Ÿ‘€ See it work
30
31
 
31
- This is a real run against the small demo app bundled in this repository. The screenshot was taken by SceneScout; the badge sitting on top of a button and the missing chart are two of the nine findings it filed.
32
+ This is a real run against the small demo app bundled in this repository. The app has bugs planted in it on purpose, and two of them are visible on its dashboard:
32
33
 
33
- <p align="center"><img src="examples/screenshots/dashboard.png" alt="The demo app's dashboard: a yellow badge covers the All orders button, and the weekly chart image is broken" width="720" /></p>
34
+ <p align="center"><img src="examples/screenshots/dashboard-annotated.png" alt="The demo app's dashboard with two defects outlined in red: 1, a yellow badge covering the All orders button; 2, the weekly chart image failing to load" width="760" /></p>
35
+
36
+ **The broken chart is the demo app's bug, not this page's** โ€” it is one of the ten findings SceneScout filed, next to the badge sitting on a button. The red callouts were added for this README; the [unmarked screenshots](examples/screenshots/) are the ones the engine took.
34
37
 
35
38
  An excerpt of the report it wrote โ€” [read the whole thing](examples/report.md):
36
39
 
@@ -41,19 +44,22 @@ An excerpt of the report it wrote โ€” [read the whole thing](examples/report.md)
41
44
  > **๐Ÿ”ด [HIGH] Filtering orders by Archived fails, and the page shows an empty table instead of an error**
42
45
  > Evidence: `GET /api/orders?status=archived โ†’ HTTP 500`
43
46
  >
44
- > **๐ŸŸ  [MEDIUM] The "New: bulk import" badge sits on top of the All orders button**
47
+ > **๐ŸŸ  [MEDIUM] The "New: bulk import" badge sits on top of the All orders button** *(callout 1)*
45
48
  > Evidence: `"All orders" overlaps "New: bulk import" (81%)` โ€” measured from layout boxes, no screenshot needed.
46
49
  >
50
+ > **๐ŸŸก [LOW] The dashboard chart image is missing** *(callout 2)*
51
+ > Evidence: `GET /img/weekly-chart.png โ†’ HTTP 404`
52
+ >
47
53
  > **Gap ledger โ€” what was NOT tested:** 4/7 visited routes never design-audited ยท single-role run, so permission boundaries are untested
48
54
 
49
- Every finding comes with a repro trace and a Playwright regression-test skeleton. Try it yourself in two minutes: `npm run demo:serve`, then `/scenescout --url http://127.0.0.1:4173` โ€” see [demo-app/](demo-app/). It also documents [one defect the tool deliberately does not flag](demo-app/README.md#what-it-deliberately-does-not-catch).
55
+ Every finding comes with a repro trace and a Playwright regression-test skeleton. To try it yourself, clone this repository, run `npm run demo:serve`, then `/scenescout --url http://127.0.0.1:4173` โ€” see [demo-app/](demo-app/). Its README lists every seeded defect and which oracle catches it.
50
56
 
51
57
  ---
52
58
 
53
59
  ## โœจ Why it's different
54
60
 
55
61
  - ๐Ÿง  **Claude is the brain โ€” no API key.** The engine contains no LLM. Exploration runs on your Claude Code subscription; SceneScout just gives it deterministic tools.
56
- - ๐Ÿ“ **Structured scene, not pixels.** The agent reads element lists *with layout geometry*, not screenshots. Overlap and off-screen bugs are computed from boxes โ€” deterministic, no vision guessing. (Screenshots exist only for pixel-native residue like broken images.)
62
+ - ๐Ÿ“ **Structured scene, not pixels.** The agent reads element lists *with layout geometry*, not screenshots. Overlap and off-screen bugs are computed from boxes โ€” deterministic, no vision guessing. Images that failed to load are read from the DOM too. (Screenshots exist only for pixel-native residue like a canvas or a rendering glitch.)
57
63
  - ๐Ÿ›ก๏ธ **Read-only by default, enforced on the wire.** Destructive actions are blocked at the network layer, not by asking the model nicely. Opt into writes only against disposable data.
58
64
  - โœ… **Completion is a contract, not a vibe.** The engine knows the app's routes and *refuses* to file an "extensive" report while any known route is unvisited, unexercised, or un-audited. "Explored a bit and stopped" is structurally impossible.
59
65
  - ๐Ÿงญ **It remembers.** UI states are fingerprinted and stored in the project's `.scenescout/`. Run N+1 skips what run N already covered, and every run starts smarter than the last.
@@ -68,13 +74,13 @@ SceneScout needs only a URL. Give it the source code as well and it gets noticea
68
74
  |---|---|---|
69
75
  | **You run it from** | the app's repository | any folder โ€” an empty `qa/` directory is fine |
70
76
  | **It plays the role of** | a developer-tester who can read the code | a black-box QA tester, like a person with a browser |
71
- | **How it finds pages** | ๐Ÿ“‚ reads file-based routes from the source (Next.js, SvelteKit, Nuxt) **and** follows links. Code-routed apps fall back to links | ๐Ÿ”— follows same-origin links only โ€” pages nothing links to, or on another subdomain, stay unknown |
77
+ | **How it finds pages** | ๐Ÿ“‚ reads routes from the source **and** follows links: file-based routing (Next.js, SvelteKit, Nuxt) and router configuration written in code (React Router, Vue Router, Angular). Routes built at runtime are not seen | ๐Ÿ”— follows same-origin links only โ€” pages nothing links to, or on another subdomain, stay unknown |
72
78
  | **"Did we cover everything?"** | checked against the routes found in source *plus* discovered links โ€” an unvisited one blocks the report | checked against the pages it managed to discover |
73
79
  | **Setup it figures out** | framework, dev command, saved Playwright logins (`playwright/.auth/`), whether the app uses `data-testid` | none โ€” you pass the URL, and the path to a login state if the app needs one |
74
80
  | **What a finding looks like** | the symptom, **plus** the file behind it and a suggested fix | the symptom, a repro trace, and a regression-test skeleton |
75
81
  | **Typical target** | `localhost` while you build | staging, a preview deploy, a client's site |
76
82
 
77
- **Why the codebase helps.** The agent driving SceneScout is Claude Code, which can already read your repository. With the source at hand โ€” and a file-routed framework โ€” it knows the app's static routes before opening the browser, so coverage is measured against the real app instead of whatever happened to be linked. It can also check a suspicion against the code before reporting it: "there is no way to export this table" is a much stronger finding once the agent has confirmed no export handler exists. And when something breaks it can open the component or handler responsible and tell you *where* and *how* to fix it โ€” "the save button does nothing" becomes "`OrderForm` swallows the rejected promise in `onSubmit`; surface the error and re-enable the button".
83
+ **Why the codebase helps.** The agent driving SceneScout is Claude Code, which can already read your repository. With the source at hand it knows the app's static routes before opening the browser, so coverage is measured against the real app instead of whatever happened to be linked. It can also check a suspicion against the code before reporting it: "there is no way to export this table" is a much stronger finding once the agent has confirmed no export handler exists. And when something breaks it can open the component or handler responsible and tell you *where* and *how* to fix it โ€” "the save button does nothing" becomes "`OrderForm` swallows the rejected promise in `onSubmit`; surface the error and re-enable the button".
78
84
 
79
85
  **Why it still works without it.** Everything SceneScout *observes* comes from the running page โ€” elements, layout geometry, console and network errors, design-audit scores, task-ease measurements โ€” and none of that needs source code. Point it at a URL you are allowed to test and it behaves like a thorough QA tester: it explores, reproduces, and files findings with evidence.
80
86
 
@@ -87,7 +93,7 @@ SceneScout needs only a URL. Give it the source code as well and it gets noticea
87
93
  ```
88
94
 
89
95
  > [!IMPORTANT]
90
- > Only test sites you own or are authorized to test. A remote environment is more likely to hold real data. The default **read-only** mode blocks `PUT`/`PATCH`/`DELETE` and destructive-looking requests, but an ordinary form submission (a plain `POST`: contact form, comment, order, signup) still reaches the server and can create a record. On a site with real data, tell the agent which forms not to submit. See the [safety model](#-safety-model).
96
+ > Only test sites you own or are authorized to test. A remote environment is more likely to hold real data, so for a remote URL with no source the skill attaches in **`observe`** mode: nothing but `GET` requests leaves the page. The default **read-only** mode blocks `PUT`/`PATCH`/`DELETE` and destructive-looking requests, but an ordinary form submission (a plain `POST`: contact form, comment, order, signup) still reaches the server and can create a record. Say so when that is acceptable on your target. See the [safety model](#-safety-model).
91
97
 
92
98
  ---
93
99
 
@@ -103,39 +109,29 @@ SceneScout needs only a URL. Give it the source code as well and it gets noticea
103
109
 
104
110
  ### 1๏ธโƒฃ Install
105
111
 
106
- Pick one. All three end with the same 24 tools.
112
+ It is on npm. Nothing to clone:
107
113
 
108
- **A ยท Claude Code plugin** โ€” the skill and the server in one step:
114
+ ```bash
115
+ npx -y scenescout install # skill + Chromium (~150 MB, one-time) + registers the server with Claude Code
116
+ ```
117
+
118
+ **Prefer a Claude Code plugin?** The skill and the server arrive together:
109
119
 
110
120
  ```
111
121
  /plugin marketplace add brunoboto96/SceneScout
112
122
  /plugin install scenescout@scenescout-marketplace
113
123
  ```
114
124
 
115
- Then download the browser once: `npx -y scenescout install --browser-only`. The command is `/scenescout:scenescout`.
116
-
117
- **B ยท npm, for Claude Code or any other MCP client:**
125
+ Then download the browser once with `npx -y scenescout install --browser-only`. The command becomes `/scenescout:scenescout`. A plugin's skill comes from this repository and its server from the latest npm release, so right after a release lands here the two can differ for a short while; `/plugin marketplace update scenescout-marketplace` brings the skill up to date.
118
126
 
119
- ```bash
120
- npx -y scenescout install # skill + Chromium (~150 MB, one-time) + registers the server with Claude Code
121
- ```
122
-
123
- Using a different client? Skip the registration and [add the server to its config](#-other-mcp-clients) instead: `npx -y scenescout install --browser-only`.
124
-
125
- **C ยท From source**, to hack on it:
126
-
127
- ```bash
128
- git clone https://github.com/brunoboto96/SceneScout.git scenescout && cd scenescout
129
- npm install # installs dependencies and builds
130
- npm run setup # same as `scenescout install`, pointed at this checkout
131
- ```
127
+ **Another MCP client?** Run `npx -y scenescout install --browser-only` and [add the server to its config](#-other-mcp-clients).
132
128
 
133
129
  <details>
134
- <summary>What <code>install</code> / <code>npm run setup</code> actually does</summary>
130
+ <summary>What <code>install</code> actually does</summary>
135
131
 
136
- 1. links the `/scenescout` skill into `~/.claude/skills/` (or `$CLAUDE_CONFIG_DIR/skills/`) โ€” a `scenescout` folder it didn't create is moved aside to a `.backup-โ€ฆ` copy, never deleted. When run through `npx` it copies instead of linking, because the npx cache is temporary,
132
+ 1. puts the `/scenescout` skill into `~/.claude/skills/` (or `$CLAUDE_CONFIG_DIR/skills/`) โ€” a `scenescout` folder it didn't create is moved aside to a `.backup-โ€ฆ` copy, never deleted,
137
133
  2. downloads the Chromium build SceneScout drives (skipped if you already have it),
138
- 3. registers the MCP server with Claude Code at user scope, using an **absolute** node path so it works under nvm/fnm.
134
+ 3. registers the MCP server with Claude Code at user scope. Run through `npx`, the launcher is `npx -y scenescout serve`, with the absolute path of `npx` where one sits beside node, so it works under nvm/fnm. From a clone or a global install it is the absolute node path plus that install's `dist/mcp-server.js`.
139
135
 
140
136
  Re-run it any time: after moving the folder or switching node versions it refreshes the stored paths. It exits non-zero if any step failed, so it is safe to chain. Opt out of a step with `--no-register` or `--skip-browser`.
141
137
 
@@ -150,15 +146,15 @@ claude mcp add --scope user scenescout -- npx -y scenescout serve
150
146
  ### 2๏ธโƒฃ Check it
151
147
 
152
148
  ```bash
153
- npx -y scenescout doctor # routes B and C (from source: npm run doctor)
154
- npx -y scenescout doctor --engine # route A, or another MCP client: node + build + browser only
149
+ npx -y scenescout doctor # everything, for the default install
150
+ npx -y scenescout doctor --engine # plugin install or another MCP client: node + build + browser only
155
151
  ```
156
152
 
157
153
  Every line should be a โœ“. Anything that isn't prints the exact command that fixes it. Then **start a fresh session** in your client so it picks up the new tools.
158
154
 
159
155
  ### 3๏ธโƒฃ Run it
160
156
 
161
- No app handy? `npm run demo:serve` in a source checkout starts the [demo app](demo-app/) on `http://127.0.0.1:4173`.
157
+ No app handy? Clone this repository and run `npm run demo:serve`: the [demo app](demo-app/) starts on `http://127.0.0.1:4173`.
162
158
 
163
159
  From Claude Code, inside the project you want to test (or, for a [remote URL](#-two-ways-to-use-it), any folder):
164
160
 
@@ -168,7 +164,7 @@ From Claude Code, inside the project you want to test (or, for a [remote URL](#-
168
164
 
169
165
  The skill scans the project (if there is one), attaches read-only, explores, and writes findings to `.scenescout/report.md`. That's it.
170
166
 
171
- **Common flags** โ€” `--level minimal|medium|extensive` ยท `--url <app>` ยท `--role <name\|path>` (a Playwright storage-state to explore as: a name found by the scan, or a path to the JSON file) ยท `--safe-write` / `--allow-destructive`.
167
+ **Common flags** โ€” `--level minimal|medium|extensive` ยท `--url <app>` ยท `--role <name\|path>` (a Playwright storage-state to explore as: a name found by the scan, or a path to the JSON file) ยท `--observe` / `--safe-write` / `--allow-destructive`.
172
168
 
173
169
  ---
174
170
 
@@ -234,6 +230,7 @@ That refusal *is* the guarantee: an extensive report can only exist when nothing
234
230
 
235
231
  ## ๐Ÿ”’ Safety model
236
232
 
233
+ - ๐Ÿ”ต **`observe`** (`--observe`) lets nothing but `GET` requests leave the page. The one exception is what a session needs in order to exist: logging in, logging out and refreshing a token. Signing up, changing or resetting a password and creating users are blocked like any other write. WebSocket frames are not inspected; the engine says so when the app opens a socket. It is what the skill picks for a remote URL with no source, where an ordinary form POST would create a real record. Forms that could not be submitted are listed in the gap ledger.
237
234
  - ๐ŸŸข **`read-only` by default.** Destructive-labeled elements (delete/revoke/archive/โ€ฆ) **and** all `PUT/PATCH/DELETE` + destructive `POST`s are blocked at the network layer โ€” see [`src/engine/policy.ts`](src/engine/policy.ts). Non-destructive `POST`s are allowed, because submitting forms is how a tester finds validation bugs โ€” so read-only means *nothing existing is changed or removed*, not *nothing is ever created*.
238
235
  - ๐ŸŸก **`safe-write`** (`--safe-write`) lets the agent create data and edit/delete **only what it created** this run โ€” never pre-existing records.
239
236
  - ๐Ÿ”ด **`destructive`** (`--allow-destructive`) allows everything, and only ever when *you* confirm the environment is disposable. The skill will never choose this itself.
@@ -258,22 +255,22 @@ A `๐Ÿ›ก WRITE-POLICY blocked` notice is the safety net doing its job, not an app
258
255
 
259
256
  ## ๐Ÿฉบ Troubleshooting
260
257
 
261
- Run `npm run doctor` first โ€” it checks every setup item below (everything but the last row, which is about your app) and prints the fix.
258
+ Run `npx -y scenescout doctor` first โ€” it checks every setup item below (everything but the last row, which is about your app) and prints the fix.
262
259
 
263
260
  | Symptom | Cause and fix |
264
261
  |---|---|
265
- | `/scenescout` isn't a known command | The skill isn't linked, or the session predates it. `npm run setup`, then start a **fresh** Claude Code session. |
266
- | The `scout_*` tools don't appear | The MCP server isn't registered, or points at an old path. `npm run setup` re-registers it; `claude mcp list` should show `scenescout` as connected. |
267
- | `npm install` fails at the build step | The build needs the dev dependencies (TypeScript). Don't pass `--omit=dev` or set `NODE_ENV=production` when installing from a clone. |
268
- | *"Executable not found in $PATH"* | The server was registered with a bare `node`. `npm run setup` registers the absolute path. |
262
+ | `/scenescout` isn't a known command | The skill isn't linked, or the session predates it. `npx -y scenescout install`, then start a **fresh** Claude Code session. |
263
+ | The `scout_*` tools don't appear | The MCP server isn't registered, or points at an old path. `npx -y scenescout install` re-registers it; `claude mcp list` should show `scenescout` as connected. |
264
+ | *"Executable not found in $PATH"* | The server was registered with a bare `node`. `npx -y scenescout install` registers an absolute path. |
265
+ | Installed as a plugin, and the tools fail with *"Executable not found in $PATH: npx"* | A plugin starts the server with a bare `npx`, which Claude Code can only find if it was launched from an environment that has Node on its `PATH`. Under nvm or fnm that means starting Claude Code from a terminal, not from a dock or launcher. Or use `npx -y scenescout install` instead, which registers the absolute path of `npx`. |
269
266
  | *"Executable doesn't exist โ€ฆ chromium"* | The browser download was skipped or failed. `npx playwright install chromium` (on Linux add `--with-deps`). |
270
- | Tools broke after moving the folder or changing node version | The registration stores absolute paths. `npm run setup` refreshes them. |
267
+ | Tools broke after moving the folder or changing node version | The registration stores absolute paths. `npx -y scenescout install` refreshes them. |
271
268
  | Attach fails or every route lands on the login page | Your app isn't running at `--url`, or the `--role` storage state has expired โ€” regenerate it the way your project's Playwright setup does. |
272
269
 
273
270
  ### โฌ†๏ธ Upgrading from an older version
274
271
 
275
- - **Tools are now `scout_*`.** Up to v0.23 they were prefixed `ft_`. The rename happened before the first npm release, with no aliases, so an agent's context carries one tool list rather than two. Re-run `npm run setup` so the installed skill matches the server.
276
- - **Earlier names.** This tool was previously called SceneCraft (and, before that, frontend-tester). `npm run setup` cleans up after both: it removes the old skill link and the old `scenecraft` MCP registration when they point at this install, and the first attach in a project moves its `.scenecraft/` memory folder to `.scenescout/` so earlier coverage and findings carry over.
272
+ - **Tools are now `scout_*`.** Up to v0.23 they were prefixed `ft_`. The rename happened before the first npm release, with no aliases, so an agent's context carries one tool list rather than two. Re-run `npx -y scenescout install` so the installed skill matches the server.
273
+ - **Earlier names.** This tool was previously called SceneCraft (and, before that, frontend-tester). `scenescout install` cleans up after both: it removes the old skill link and the old `scenecraft` MCP registration when they point at this install, and the first attach in a project moves its `.scenecraft/` memory folder to `.scenescout/` so earlier coverage and findings carry over.
277
274
 
278
275
  ### ๐Ÿงน Uninstall
279
276
 
@@ -282,13 +279,13 @@ claude mcp remove --scope user scenescout
282
279
  rm -rf ~/.claude/skills/scenescout
283
280
  ```
284
281
 
285
- Then delete the clone. Per-project memory lives in each tested project's `.scenescout/` folder; delete it there if you want it gone.
282
+ Nothing else is installed: `npx` runs the package from npm's cache. Per-project memory lives in each tested project's `.scenescout/` folder; delete it there if you want it gone.
286
283
 
287
284
  ---
288
285
 
289
286
  ## ๐Ÿ”Œ Other MCP clients
290
287
 
291
- The engine is a plain MCP server over stdio, so any client can drive it. The server entry is always the same command โ€” `npx -y scenescout serve` โ€” only the config file differs. Download the browser once with `npx -y scenescout install --browser-only`.
288
+ The engine is a plain MCP server over stdio, so any client can drive it. The Claude Code route is the one this project tests. The entries below follow each client's own documentation for a local stdio server and have not been run by the maintainer; if one is out of date, a correction is welcome (say which client version you checked). The server entry is always the same command โ€” `npx -y scenescout serve` โ€” only the config file differs. Download the browser once with `npx -y scenescout install --browser-only`.
292
289
 
293
290
  <details>
294
291
  <summary><strong>Cursor</strong> โ€” <code>~/.cursor/mcp.json</code> (or <code>.cursor/mcp.json</code> in a project)</summary>
@@ -327,10 +324,62 @@ args = ["-y", "scenescout", "serve"]
327
324
 
328
325
  </details>
329
326
 
327
+ <details>
328
+ <summary><strong>Gemini CLI</strong> โ€” <code>~/.gemini/settings.json</code> (or <code>.gemini/settings.json</code> in a project)</summary>
329
+
330
+ ```json
331
+ {
332
+ "mcpServers": {
333
+ "scenescout": { "command": "npx", "args": ["-y", "scenescout", "serve"] }
334
+ }
335
+ }
336
+ ```
337
+
338
+ </details>
339
+
340
+ <details>
341
+ <summary><strong>Windsurf</strong> โ€” <code>~/.codeium/windsurf/mcp_config.json</code></summary>
342
+
343
+ ```json
344
+ {
345
+ "mcpServers": {
346
+ "scenescout": { "command": "npx", "args": ["-y", "scenescout", "serve"] }
347
+ }
348
+ }
349
+ ```
350
+
351
+ </details>
352
+
353
+ <details>
354
+ <summary><strong>Cline</strong> โ€” MCP Servers โ†’ Configure โ†’ Configure MCP Servers (or <code>~/.cline/mcp.json</code> for the CLI)</summary>
355
+
356
+ ```json
357
+ {
358
+ "mcpServers": {
359
+ "scenescout": { "command": "npx", "args": ["-y", "scenescout", "serve"], "disabled": false, "autoApprove": [] }
360
+ }
361
+ }
362
+ ```
363
+
364
+ </details>
365
+
366
+ <details>
367
+ <summary><strong>Zed</strong> โ€” <code>settings.json</code> (command palette: <code>zed: open settings file</code>)</summary>
368
+
369
+ ```json
370
+ {
371
+ "context_servers": {
372
+ "scenescout": { "command": "npx", "args": ["-y", "scenescout", "serve"], "env": {} }
373
+ }
374
+ }
375
+ ```
376
+
377
+ </details>
378
+
330
379
  <details>
331
380
  <summary><strong>Anything else</strong></summary>
332
381
 
333
- Most clients accept the same `mcpServers` JSON shape shown for Cursor. From a source checkout, the command is `node` with the absolute path to `dist/mcp-server.js`.
382
+ Most clients accept the same `mcpServers` JSON shape shown for Cursor.
334
383
 
335
384
  </details>
336
385
 
@@ -366,7 +415,7 @@ src/
366
415
  memory.ts cross-run storage + finding dedup
367
416
  report.ts the gap ledger + report generation
368
417
  โ€ฆ collector ยท dispatch ยท fixtures ยท authloss ยท reaper
369
- scripts/ the 11 test suites (smoke/ holds the real-browser ones)
418
+ scripts/ the 12 test suites (smoke/ holds the real-browser ones)
370
419
  test-app/ fixtures for the real-browser smoke tests
371
420
  skills/scenescout/ the Claude Code skill (SKILL.md)
372
421
  docs/adr/ why it's built this way
@@ -391,14 +440,18 @@ The load-bearing choices are recorded as ADRs โ€” read the relevant one before c
391
440
 
392
441
  ## ๐Ÿ”ง Development
393
442
 
443
+ Working on SceneScout itself is the only reason to clone it:
444
+
394
445
  ```bash
395
- npm run build # tsc
396
- npm test # build + 11 suites: scan, oracle, policy, fixture, dispatch, design,
397
- # contract, memory, install, smoke, mcp-check
398
- npm run dev # run the CLI from source (tsx)
446
+ git clone https://github.com/brunoboto96/SceneScout.git scenescout && cd scenescout
447
+ npm install # installs dependencies and builds
448
+ npm run setup # same as `scenescout install`, but registers THIS checkout (the skill is linked, so edits are live)
449
+ npm test # build + 12 suites: scan, oracle, policy, fixture, dispatch, design,
450
+ # contract, memory, install, hygiene, smoke, mcp-check
451
+ npm run demo # regenerate examples/ from the demo app
399
452
  ```
400
453
 
401
- Contributing? Start with [VISION.md](VISION.md) (what is in scope) and [CONTRIBUTING.md](CONTRIBUTING.md) (how changes land), then see [CLAUDE.md](CLAUDE.md) for the house rules โ€” chiefly: bug fixes need a regression test at the cheapest layer that can fail, keep the repo project-agnostic (ADR 6), and `npm run build && npm test` must pass before committing.
454
+ Contributing? Start with [VISION.md](VISION.md) (what is in scope) and [CONTRIBUTING.md](CONTRIBUTING.md) (how changes land), then see [CLAUDE.md](CLAUDE.md) for the house rules โ€” chiefly: bug fixes need a regression test at the cheapest layer that can fail, keep the repo project-agnostic (ADR 6), and `npm test` must pass.
402
455
 
403
456
  ## ๐Ÿ” Security
404
457
 
@@ -411,7 +464,7 @@ Found a way past the write policy, or another security problem? Please report it
411
464
  <details>
412
465
  <summary><strong>Full capability list</strong> โ€” every behavior, for the curious</summary>
413
466
 
414
- - **Structured render-state, not pixels.** Element lists with geometry; screenshots reserved for pixel-native residue (broken images, canvas).
467
+ - **Structured render-state, not pixels.** Element lists with geometry; screenshots reserved for pixel-native residue (canvas, rendering glitches). Images that failed to load are reported from the DOM, including ones whose URL answered 200 with something that is not an image.
415
468
  - **Diff snapshots with stable refs.** Re-snapshots return only what changed (10.7 kB โ†’ 0.7 kB on a 130-element page); old refs stay valid.
416
469
  - **Geometry oracles.** Overlap and off-screen defects computed from layout boxes.
417
470
  - **Oracles after every action.** Console errors, page errors, failed requests, HTTP 4xx/5xx drained into every tool result.
package/dist/cli.js CHANGED
@@ -187,7 +187,7 @@ async function install(flags) {
187
187
  }
188
188
  }
189
189
  if (failed) {
190
- console.log("\nSetup is incomplete โ€” fix the lines marked โœ— or ยท above, then run: npm run doctor");
190
+ console.log("\nSetup is incomplete โ€” fix the lines marked โœ— or ยท above, then run: scenescout doctor");
191
191
  process.exitCode = 1;
192
192
  return;
193
193
  }
@@ -196,7 +196,7 @@ async function install(flags) {
196
196
  return;
197
197
  }
198
198
  console.log("\nStart a FRESH Claude Code session, then in any project run: /scenescout");
199
- console.log("Something off? Run: npm run doctor");
199
+ console.log("Something off? Run: scenescout doctor");
200
200
  }
201
201
  async function doctor(flags) {
202
202
  const checks = diagnose({