page-harness 0.1.3 → 0.1.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 CHANGED
@@ -1,107 +1,100 @@
1
- # page-harness
1
+ <p align="center">
2
+ <img src="https://unpkg.com/page-harness@0.1.5/docs/logo.svg" width="72" alt="page-harness logo">
3
+ </p>
2
4
 
3
- [中文](./README.zh-CN.md)
5
+ <h1 align="center">page-harness</h1>
4
6
 
5
- Point it at any running frontend and the page gets a **Pick / Artifacts / Chat** dock, driven by the coding agent CLI already on your machine (Claude Code, Codex, Cursor Agent, CodeBuddy Code or OpenCode). No sandbox, no accounts, no changes to your app.
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/page-harness"><img alt="npm page-harness" src="https://img.shields.io/npm/v/page-harness?label=npm&labelColor=16161A&color=7C5CFF&style=flat-square"></a>
9
+ <a href="./LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-7C5CFF?labelColor=16161A&color=7C5CFF&style=flat-square"></a>
10
+ <img alt="Node" src="https://img.shields.io/badge/node-%E2%89%A520.11-7C5CFF?labelColor=16161A&color=7C5CFF&style=flat-square">
11
+ </p>
6
12
 
7
- ```bash
8
- npx page-harness http://localhost:5173 --project ./my-app --agent claude
9
- # open http://127.0.0.1:17990 — it is your app, plus the dock in the bottom-right corner
13
+ <p align="center">
14
+ <b>English</b> · <a href="./README.zh-CN.md">简体中文</a>
15
+ </p>
10
16
 
11
- npx page-harness --no-agent http://localhost:5173 # Pick and Notes only; no agent CLI
12
- npx page-harness # no URL: review-only home page and a bookmarklet
13
- ```
17
+ <p align="center">
18
+ <a href="#overview">Overview</a> ·
19
+ <a href="#quick-start">Quick start</a> ·
20
+ <a href="#product-tour">Product tour</a> ·
21
+ <a href="#features">Features</a> ·
22
+ <a href="#usage">Usage</a> ·
23
+ <a href="#documentation">Docs</a> ·
24
+ <a href="#development">Development</a>
25
+ </p>
14
26
 
15
- ## What you get
27
+ <p align="center">
28
+ <img src="https://unpkg.com/page-harness@0.1.5/docs/hero.webp" width="720" alt="page-harness promo video (0:30)">
29
+ </p>
16
30
 
17
- - **Pick** — click an element on the page and choose what to do with it: **Quote in chat** (selector, text and outer HTML go with your next message; Shift+click quotes directly), **Comment**, **Edit** (no-source sites) or **Live candidates**. Live: choose an element, describe the change and the agent writes 2–4 candidates straight into your source; you flip between them on the page, compare side by side, tune parameters, refine one, then accept or discard.
18
- - **Chat** — a draggable, resizable chat window. Streaming replies with Markdown and syntax highlighting, collapsible thinking, tool cards, changed-file lists, image/file attachments (paste, drop or pick), a per-chat queue you can reorder, edit or withdraw, Stop / Retry, multiple chats, per-chat agent and model.
19
- - **Page control** (off by default) — let the agent read the page and click, type, select and scroll on it. A banner shows when it is on; Stop takes it back at any time.
20
- - **Artifacts** — the agent writes reports, mockups, JSON, images and other files through MCP. Preview them in tabs with version history: Markdown, sandboxed HTML (desktop / mobile widths), structured JSON, code, images; copy, download, export to PNG or PDF.
21
- - **Notes** — comment on or edit elements in place, threaded replies, resolve and per-page approval; teammates on your network can join as reviewers with `--share`. Works on sites you have no source for.
22
- - **Questions** — the agent can ask you multiple-choice questions or a short form and wait for the answer.
23
- - **History** — every chat is an append-only event log on disk. Browse, search and export it at `http://127.0.0.1:17991/__ph/history`, or from the chat switcher.
31
+ <p align="center"><sub>0:30 · 1080p</sub></p>
24
32
 
25
- ## Requirements
33
+ ## Overview
26
34
 
27
- - Node.js 20.11 or newer.
28
- - At least one agent CLI on `PATH`, signed in:
29
- - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (`claude`)
30
- - [Codex](https://github.com/openai/codex) (`codex`)
31
- - [Cursor Agent](https://docs.cursor.com/en/cli/overview) (`cursor-agent`)
32
- - [CodeBuddy Code](https://www.codebuddy.ai/cli) (`codebuddy`, `npm i -g @tencent-ai/codebuddy-code`)
33
- - [OpenCode](https://opencode.ai) (`opencode`, `npm i -g opencode-ai`)
35
+ **Turn any running web page into a workspace for your coding agent.**
34
36
 
35
- page-harness detects which ones are installed and shows them in the banner. Use `--claude-path`, `--codex-path`, `--cursor-path`, `--codebuddy-path` or `--opencode-path` for non-standard locations. Agents that are not installed stay in the chat's agent picker, greyed out, with the install command.
37
+ Click the thing you want changed and tell your agent what to do, right on the page: Pick, Chat and Artifacts, driven by the agent CLI already on your machine (Claude Code, Codex, Cursor Agent, CodeBuddy Code, OpenCode). For feedback only, `--no-agent` keeps just Pick and Notes; run it with no URL and you get a home page with a **✦ Page-Harness** bookmarklet that works on any site.
36
38
 
37
- What each agent supports:
39
+ Describing UI in a terminal is painful: "the second button in the card on the left, make it a bit softer". With page-harness you just click the thing on the page and talk to your agent right there. It writes the code, your dev server reloads, you see the result on the same page.
38
40
 
39
- | | Claude Code | Codex | Cursor Agent | CodeBuddy Code | OpenCode |
40
- |---|---|---|---|---|---|
41
- | Streaming text / thinking | ✓ | ✓ | ✓ | ✓ | per block¹ |
42
- | Tool cards, changed files | ✓ | ✓ | ✓ | ✓ | ✓¹ |
43
- | Resume a chat | ✓ | ✓ | ✓ | ✓ | ✓ |
44
- | Model list | ✓ | ✓ | ✓ | ✓ (from `--help`) | ✓ (`opencode models`) |
45
- | Reasoning effort | – | ✓ | – | ✓ (`--effort`) | ✓ (`--variant`) |
46
- | Image attachments | ✓ | ✓ | file path in prompt | ✓ | ✓ (`--file`) |
41
+ ## Quick start
47
42
 
48
- ¹ `opencode run --format json` reports text, reasoning and tool calls once each part has finished, so replies arrive a block at a time and a tool card opens and closes together.
43
+ One line. Point it at your dev server:
49
44
 
50
- ## Usage
45
+ ```bash
46
+ npx page-harness http://localhost:5173 --project ./my-app
47
+ npx page-harness --no-agent http://localhost:5173 # review only: Pick and Notes, no agent CLI
48
+ npx page-harness # no URL: home page with a bookmarklet
49
+ ```
51
50
 
52
- ```text
53
- page-harness [frontend-url] [options]
51
+ Open **http://127.0.0.1:17990**. That is your app as usual, plus a dock in the bottom-right corner.
54
52
 
55
- --project <dir> Project the agent works in (default: current directory)
56
- --agent <id> claude | codex | cursor | codebuddy | opencode (default: first one installed)
57
- --model <name> Default model for new chats
58
- --port <n> App port: the proxied frontend (default 17990)
59
- --control-port <n> Panel / API port (default: app port + 1, or 17991 with no URL)
60
- --host <addr> Listen address (default 127.0.0.1)
61
- --allow-host <name> Extra Host header to accept (repeatable), e.g. a LAN name
62
- --keep-host Forward the browser's Host header to the target
63
- --public-scheme <s> http | https: scheme browsers use to reach both ports (default http);
64
- https behind a load balancer that terminates TLS on the same ports
65
- --open Open the browser
66
- --live-guard-hook Install a git pre-commit hook that rejects Live candidate markers
67
- --review / --source Force review mode (no source) or source mode; default is by host
68
- --no-agent Review only. Do not detect or start an agent CLI.
69
- The dock is Pick and Notes. Implied when no URL is given.
70
- --share Let teammates on your network join as reviewers (listens on 0.0.0.0)
71
- --verbose / --quiet
72
- ```
53
+ - Needs **Node.js 20.11+** and at least one signed-in agent CLI on `PATH` (see below).
54
+ - The target can be a bare port (`3000`), `host:port` or a full URL. HMR (Vite, webpack, Next.js…) keeps working through the proxy.
55
+ - No sandbox, no accounts, no changes to your app. Everything stays in `<project>/.page-harness/`.
73
56
 
74
- `<frontend-url>` can be a bare port (`3000`), `host:port` or a full URL. Omit it to start the bookmarklet home page. Dev-server HMR (Vite, webpack, Next.js…) keeps working through the proxy, including WebSockets.
57
+ | Service | URL |
58
+ |---|---|
59
+ | Your app + dock | `http://127.0.0.1:17990` |
60
+ | Panel / API (control port) | `http://127.0.0.1:17991` |
61
+ | Chat history | `http://127.0.0.1:17991/__ph/history` |
62
+ | Bookmarklet home (no URL) | `http://127.0.0.1:17991` |
75
63
 
76
- ### Review only (`--no-agent`)
64
+ ### Other ways to run
77
65
 
78
- ```bash
79
- npx page-harness --no-agent http://localhost:5173
80
- ```
66
+ | Option | When to use it |
67
+ |---|---|
68
+ | `npx page-harness <url>` | The standard setup above: your app behind the proxy, with Pick, Chat and Artifacts driven by an agent CLI |
69
+ | `--no-agent <url>` | Feedback only: Pick and Notes, no agent CLI needed ([details](#review-only---no-agent)) |
70
+ | no URL | A home page with the **✦ Page-Harness** bookmarklet, to leave notes on any site without a proxy ([details](#bookmarklet-no-url)) |
71
+ | `--share` | Teammates on your network join as reviewers with a link ([details](#team-review---share)) |
81
72
 
82
- No agent CLI is detected or started, and MCP is refused. The dock is **Pick** and **Notes** only: comment, edit, reply, resolve and approve. Chat, Artifacts, Live, page control and questions are not shown. Notes are still saved in the project's `review.json`, under the **target** site's host (not the proxy's `127.0.0.1:17990`).
73
+ ## Product tour
83
74
 
84
- ### Bookmarklet (no URL)
75
+ ### Review only
85
76
 
86
- ```bash
87
- npx page-harness
88
- # Home http://127.0.0.1:17991
89
- ```
77
+ **Pick and Notes, nothing else.** With `--no-agent` no agent CLI is started. Pick an element, leave a comment or an edit, reply, resolve and approve per page. [Details →](#review-only---no-agent)
90
78
 
91
- This starts only the control server, always in review-only mode. The home page has a **PH Review** button: drag it to the bookmarks bar, open any site and click it. The overlay is injected into that page (no reverse proxy) inside a Shadow DOM, so the host page's CSS does not restyle the dock. The source select chooses where the script loads from:
79
+ <p align="center"><img src="https://unpkg.com/page-harness@0.1.5/docs/review-only.png" width="720" alt="Page notes panel in review-only mode"></p>
92
80
 
93
- - **This server** — `http://127.0.0.1:<control-port>/__ph/overlay.js`. Works on http pages.
94
- - **jsDelivr** — `https://cdn.jsdelivr.net/npm/page-harness@<version>/dist/client/page/overlay.js`. Use this on https pages, and only after that version is published to npm.
81
+ ### Bookmarklet home
95
82
 
96
- Notes are written to this local server and grouped by site (`location.host`, including a non-default port). The home page lists sites on the left and that site's notes on the right, with Export Markdown, Export JSON and Copy prompt. The copied prompt calls this control server and includes `host=` so an agent only pulls that site:
83
+ **One button to drag.** Run `npx page-harness` with no URL and the home page has a single **✦ Page-Harness** button. Drag it to the bookmarks bar. [Details →](#bookmarklet-no-url)
97
84
 
98
- ```text
99
- GET http://127.0.0.1:17991/__ph/api/review?scope=all&path=%2F&page=1&pageSize=20&host=shop.example.com
100
- ```
85
+ <p align="center"><img src="https://unpkg.com/page-harness@0.1.5/docs/home.png" width="520" alt="Home page with the ✦ Page-Harness button"></p>
101
86
 
102
- The same `host` query works on the paging API when you want one site. Omit it and the API still returns every site, as before.
87
+ ### Notes on any site
88
+
89
+ **Click the bookmark on any page.** The dock is injected into that page in a Shadow DOM, with no proxy, and notes are saved to your local server, grouped by site.
90
+
91
+ <p align="center"><img src="https://unpkg.com/page-harness@0.1.5/docs/bookmarklet.png" width="720" alt="Bookmarklet dock on a plain page"></p>
103
92
 
104
- **Limits.** An https page usually blocks a script loaded from `http://127.0.0.1` (mixed content); switch the bookmarklet to jsDelivr so the script itself is https. Saving a note still calls the http control port. Chrome generally allows `127.0.0.1` and may ask for local-network access; the server answers `Access-Control-Allow-Private-Network` on the bookmarklet routes. Firefox and Safari often block that request as mixed content. A host page CSP that forbids connections to `127.0.0.1` blocks saving too. When the bookmarklet cannot reach the control port, use `page-harness <url> --no-agent` and review through the proxy instead. The bookmarklet carries a per-run token (`X-PH-Token`). It is visible in the bookmark and on pages where you click it; other sites cannot read or write notes without it. The unauthenticated paging API (`GET /__ph/api/review`) does not send CORS headers, so a random page cannot read notes through it.
93
+ ### My notes
94
+
95
+ **Every site's notes in one place.** Sites on the left, that site's notes on the right, with Export Markdown, Export JSON and Copy prompt for your agent.
96
+
97
+ <p align="center"><img src="https://unpkg.com/page-harness@0.1.5/docs/home-notes.png" width="720" alt="My notes view"></p>
105
98
 
106
99
  ## How it works
107
100
 
@@ -175,6 +168,101 @@ npx page-harness https://example.com --share
175
168
 
176
169
  Send the Share link (also in Settings → Team) to teammates on the same network. Opening it gives them a reviewer session for that browser; they enter a display name once and then see the page with everyone's notes and changes in real time. Reviewers can comment, edit (review mode), reply, resolve and approve. They cannot run or see the agent, chats, history, uploads or page control. Other machines without the link get `403`.
177
170
 
171
+ ## Features
172
+
173
+ | Area | Highlights |
174
+ |---|---|
175
+ | **Pick** | Click any element and **Quote in chat** (selector, text and HTML go along; Shift+click quotes directly), **Comment**, **Edit** (sites without source) or start **Live candidates**. |
176
+ | **Live candidates** | Describe a change and the agent writes 2–4 variants straight into your source. Flip between them on the page, compare side by side, tune parameters, refine one, then accept or discard. |
177
+ | **Chat** | Draggable, resizable window with streaming Markdown, collapsible thinking, tool cards, changed-file lists, image/file attachments, a reorderable per-chat queue, Stop / Retry, multiple chats with per-chat agent and model. |
178
+ | **Artifacts** | The agent writes reports, mockups, JSON and images through MCP. Preview them in tabs with version history; export to PNG or PDF. |
179
+ | **Page control (off by default)** | Let the agent read, click, type, select and scroll on the page. A banner shows while it is on; Stop takes it back any time. |
180
+ | **Notes & review** | Pin threaded comments to elements, resolve them and approve per page. Works on sites you have no source for (review mode). |
181
+ | **Team review** | `--share` lets teammates on your network join as reviewers with a link. |
182
+ | **Questions** | The agent can ask you multiple-choice questions or a short form and wait for the answer. |
183
+ | **History** | Every chat is an append-only event log on disk; browse, search and export it. |
184
+
185
+ ### Supported agents
186
+
187
+ page-harness drives the CLI you already use and detects which ones are installed:
188
+
189
+ | Agent | Command | Install |
190
+ |---|---|---|
191
+ | [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `claude` | see docs |
192
+ | [Codex](https://github.com/openai/codex) | `codex` | see docs |
193
+ | [Cursor Agent](https://docs.cursor.com/en/cli/overview) | `cursor-agent` | see docs |
194
+ | [CodeBuddy Code](https://www.codebuddy.ai/cli) | `codebuddy` | `npm i -g @tencent-ai/codebuddy-code` |
195
+ | [OpenCode](https://opencode.ai) | `opencode` | `npm i -g opencode-ai` |
196
+
197
+ Pick one with `--agent claude|codex|cursor|codebuddy|opencode` (default: the first one installed). Non-standard locations: `--claude-path`, `--codex-path`, `--cursor-path`, `--codebuddy-path`, `--opencode-path`.
198
+
199
+ | | Claude Code | Codex | Cursor Agent | CodeBuddy Code | OpenCode |
200
+ |---|---|---|---|---|---|
201
+ | Streaming text / thinking | ✓ | ✓ | ✓ | ✓ | per block¹ |
202
+ | Tool cards, changed files | ✓ | ✓ | ✓ | ✓ | ✓¹ |
203
+ | Resume a chat | ✓ | ✓ | ✓ | ✓ | ✓ |
204
+ | Model list | ✓ | ✓ | ✓ | ✓ (from `--help`) | ✓ (`opencode models`) |
205
+ | Reasoning effort | – | ✓ | – | ✓ (`--effort`) | ✓ (`--variant`) |
206
+ | Image attachments | ✓ | ✓ | file path in prompt | ✓ | ✓ (`--file`) |
207
+
208
+ ¹ `opencode run --format json` reports text, reasoning and tool calls once each part has finished, so replies arrive a block at a time and a tool card opens and closes together.
209
+
210
+ ## Usage
211
+
212
+ ```text
213
+ page-harness [frontend-url] [options]
214
+
215
+ --project <dir> Project the agent works in (default: current directory)
216
+ --agent <id> claude | codex | cursor | codebuddy | opencode (default: first one installed)
217
+ --model <name> Default model for new chats
218
+ --port <n> App port: the proxied frontend (default 17990)
219
+ --control-port <n> Panel / API port (default: app port + 1, or 17991 with no URL)
220
+ --host <addr> Listen address (default 127.0.0.1)
221
+ --allow-host <name> Extra Host header to accept (repeatable), e.g. a LAN name
222
+ --keep-host Forward the browser's Host header to the target
223
+ --public-scheme <s> http | https: scheme browsers use to reach both ports (default http);
224
+ https behind a load balancer that terminates TLS on the same ports
225
+ --open Open the browser
226
+ --live-guard-hook Install a git pre-commit hook that rejects Live candidate markers
227
+ --review / --source Force review mode (no source) or source mode; default is by host
228
+ --no-agent Review only. Do not detect or start an agent CLI.
229
+ The dock is Pick and Notes. Implied when no URL is given.
230
+ --lang <zh|en> Home page and dock language. Omit it and each browser keeps its own.
231
+ --share Let teammates on your network join as reviewers (listens on 0.0.0.0)
232
+ --verbose / --quiet
233
+ ```
234
+
235
+ `<frontend-url>` can be a bare port (`3000`), `host:port` or a full URL. Omit it to start the bookmarklet home page. Dev-server HMR (Vite, webpack, Next.js…) keeps working through the proxy, including WebSockets.
236
+
237
+ ### Review only (`--no-agent`)
238
+
239
+ ```bash
240
+ npx page-harness --no-agent http://localhost:5173
241
+ ```
242
+
243
+ No agent CLI is detected or started, and MCP is refused. The dock is **Pick** and **Notes** only: comment, edit, reply, resolve and approve. Chat, Artifacts, Live, page control and questions are not shown. Notes are still saved in the project's `review.json`, under the **target** site's host (not the proxy's `127.0.0.1:17990`).
244
+
245
+ ### Bookmarklet (no URL)
246
+
247
+ ```bash
248
+ npx page-harness
249
+ # Home http://127.0.0.1:17991
250
+ ```
251
+
252
+ This starts only the control server, always in review-only mode. The home page is one button, **✦ Page-Harness**: drag it to the bookmarks bar, open any site and click it. **Having trouble?** on the home page lists the usual reasons it does nothing. The bookmark only works for this run; drag it again after a restart. The overlay is injected into that page (no reverse proxy) inside a Shadow DOM, so the host page's CSS does not restyle the dock. The script always loads from this server: `http://127.0.0.1:<control-port>/__ph/overlay.js`.
253
+
254
+ `--lang zh` or `--lang en` sets the home page and the dock (including exported Markdown and the copied prompt). Omit it and each browser uses its saved choice, or the browser language.
255
+
256
+ Notes are written to this local server and grouped by site (`location.host`, including a non-default port). **My notes (n)** at the top right opens the notes view: sites on the left, that site's notes on the right, with Export Markdown, Export JSON and Copy prompt. The copied prompt calls this control server and includes `host=` so an agent only pulls that site:
257
+
258
+ ```text
259
+ GET http://127.0.0.1:17991/__ph/api/review?scope=all&path=%2F&page=1&pageSize=20&host=shop.example.com
260
+ ```
261
+
262
+ The same `host` query works on the paging API when you want one site. Omit it and the API still returns every site, as before.
263
+
264
+ **Limits.** An https page usually blocks a script loaded from `http://127.0.0.1` (mixed content), and saving a note still calls that http control port. Chrome generally allows `127.0.0.1` and may ask for local-network access; the server answers `Access-Control-Allow-Private-Network` on the bookmarklet routes. Firefox and Safari often block that request as mixed content. A host page CSP that forbids connections to `127.0.0.1` blocks saving too. When the bookmarklet cannot reach the control port, use `page-harness <url> --no-agent` and review through the proxy instead. The bookmarklet carries a per-run token (`X-PH-Token`). It is visible in the bookmark and on pages where you click it; other sites cannot read or write notes without it. The unauthenticated paging API (`GET /__ph/api/review`) does not send CORS headers, so a random page cannot read notes through it.
265
+
178
266
  ## Security model
179
267
 
180
268
  There is no login: it is a local developer tool and binds to `127.0.0.1` by default. Internally every surface is locked down:
@@ -207,6 +295,38 @@ team.json invite token, signing key and reviewer names (mode 6
207
295
 
208
296
  Delete the folder to start over.
209
297
 
298
+ ## FAQ
299
+
300
+ **Do I need to change my app?**
301
+ No. page-harness is a reverse proxy that injects one script into HTML responses. Your code is untouched unless the agent edits it.
302
+
303
+ **Does it work on sites I don't have the source for?**
304
+ Yes. Public URLs start in review mode: the agent leaves notes and temporary page changes instead of editing files. Force it with `--review` / `--source`.
305
+
306
+ **Which model does it use? Do I need an API key?**
307
+ Whatever your agent CLI is signed in with. page-harness has no accounts or keys of its own; pick the model per chat.
308
+
309
+ **Is it safe to expose?**
310
+ It binds to `127.0.0.1` with no login by default. `--share` opens it to your network with signed reviewer links. Agents run with non-interactive permissions inside `--project`, so only use it on projects you'd let the agent edit.
311
+
312
+ **What if Live markers end up in my code?**
313
+ page-harness scans the working tree after every Live or file-editing turn and warns you; `--live-guard-hook` installs a pre-commit hook that rejects them.
314
+
315
+ **How do I reset?**
316
+ Delete `<project>/.page-harness/`.
317
+
318
+ ## Documentation
319
+
320
+ | Start here | |
321
+ |---|---|
322
+ | [Quick start](#quick-start) | Install and the first run |
323
+ | [Usage](#usage) | All CLI options, review only and the bookmarklet |
324
+ | [How it works](#how-it-works) | Proxy, overlay, MCP tools, Live candidates, review mode |
325
+ | [Security model](#security-model) | What is locked down and how |
326
+ | [Data](#data) | What is stored in `.page-harness/` |
327
+ | [FAQ](#faq) | Common questions |
328
+ | [npm package](https://www.npmjs.com/package/page-harness) | Released versions |
329
+
210
330
  ## Development
211
331
 
212
332
  ```bash
@@ -223,6 +343,14 @@ npm run build && npm run test:e2e # browser tests against a fixture app
223
343
 
224
344
  `PH_FAKE_AGENT=1` adds a scripted `fake` agent used by the tests; it drives the real MCP endpoint, so the whole pipeline is exercised without an LLM.
225
345
 
346
+ ## Contributing
347
+
348
+ Issues and pull requests are welcome at [Tencent/page-harness](https://github.com/Tencent/page-harness).
349
+
350
+ - **Process:** Fork → create a branch → commit → open a PR
351
+ - **Before you push:** `npm run lint`, `npm run typecheck` and `npm test`; for UI changes also `npm run build && npm run test:e2e`
352
+
226
353
  ## License
227
354
 
228
355
  [MIT](./LICENSE). Bundled third-party code is listed in [THIRD_PARTY_LICENSES.md](./THIRD_PARTY_LICENSES.md).
356
+