@narumitw/pi-chrome-devtools 0.53.1 → 0.53.2
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 +88 -230
- package/dist/chunks/{browser-settings-menu-REIU7C3Q.js → browser-settings-menu-IMB6HXSU.js} +2 -2
- package/dist/chunks/{chunk-YJVYJ2L2.js → chunk-LLXOCRNF.js} +32 -16
- package/dist/chunks/chunk-LLXOCRNF.js.map +7 -0
- package/dist/chunks/{menu-H5HMVGHI.js → menu-UJETYMSB.js} +3 -3
- package/dist/index.ts +9 -10
- package/dist/index.ts.map +2 -2
- package/docs/browser-setup.md +147 -0
- package/package.json +7 -7
- package/src/display.ts +38 -0
- package/src/render.ts +6 -7
- package/src/tool-selector.ts +3 -18
- package/dist/chunks/chunk-YJVYJ2L2.js.map +0 -7
- /package/dist/chunks/{browser-settings-menu-REIU7C3Q.js.map → browser-settings-menu-IMB6HXSU.js.map} +0 -0
- /package/dist/chunks/{menu-H5HMVGHI.js.map → menu-UJETYMSB.js.map} +0 -0
package/README.md
CHANGED
|
@@ -2,189 +2,78 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@narumitw/pi-chrome-devtools) [](https://pi.dev) [](./LICENSE)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
The design is inspired by [`chrome-devtools-mcp`](https://github.com/ChromeDevTools/chrome-devtools-mcp), not guaranteed to be compatible with it.
|
|
5
|
+
Inspect browser tabs, navigate pages, evaluate JavaScript, and capture screenshots from Pi through the Chrome DevTools Protocol.
|
|
6
|
+
Use these native Pi tools for web debugging, UI validation, and browser-assisted investigation without an MCP server.
|
|
7
|
+
The design is inspired by [`chrome-devtools-mcp`](https://github.com/ChromeDevTools/chrome-devtools-mcp), but compatibility is not guaranteed.
|
|
10
8
|
|
|
11
9
|
## ✨ Features
|
|
12
10
|
|
|
13
11
|
- Lists and selects inspectable pages, navigates URLs, evaluates JavaScript, and captures PNG screenshots.
|
|
14
|
-
- Reuses an existing CDP endpoint or
|
|
15
|
-
- Recovers from stale page selections and
|
|
12
|
+
- Reuses an existing CDP endpoint or launches an isolated Chromium-family browser on first use.
|
|
13
|
+
- Recovers from stale page selections and explains browser startup or endpoint failures.
|
|
16
14
|
- Loads explicitly approved unpacked extensions only in an extension-owned Chrome for Testing or Chromium process.
|
|
17
|
-
- Uses native deferred browser tools when supported and
|
|
15
|
+
- Uses native deferred browser tools when supported and exposes allowed tools eagerly otherwise.
|
|
16
|
+
- Provides availability controls, setup guidance, status, and help through `/chrome-devtools`.
|
|
18
17
|
- Shows compact expandable results and activity only while browser tools are running.
|
|
19
18
|
- Persists reviewed tool availability while keeping browser connection settings machine-owned.
|
|
20
19
|
- Offers opt-in experimental WebMCP discovery and invocation through two fixed gateway tools without dynamically registering page-provided definitions.
|
|
21
20
|
|
|
22
21
|
## 📦 Install
|
|
23
22
|
|
|
23
|
+
Install persistently:
|
|
24
|
+
|
|
24
25
|
```bash
|
|
25
26
|
pi install npm:@narumitw/pi-chrome-devtools
|
|
26
27
|
```
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
Run once from npm:
|
|
29
30
|
|
|
30
31
|
```bash
|
|
31
32
|
pi -e npm:@narumitw/pi-chrome-devtools
|
|
32
33
|
```
|
|
33
34
|
|
|
34
|
-
Build and
|
|
35
|
+
Build and run a local checkout from the repository root:
|
|
35
36
|
|
|
36
37
|
```bash
|
|
37
38
|
npm --workspace @narumitw/pi-chrome-devtools run build
|
|
38
39
|
pi -e ./packages/pi-chrome-devtools
|
|
39
40
|
```
|
|
40
41
|
|
|
41
|
-
The package declares `dist/index.ts`, so
|
|
42
|
+
The package declares `dist/index.ts`, so build a local checkout before loading its package directory.
|
|
43
|
+
|
|
44
|
+
Pi extensions run with your user permissions.
|
|
45
|
+
Review third-party extension source before installing it.
|
|
42
46
|
|
|
43
47
|
## 🚀 Quick start
|
|
44
48
|
|
|
45
|
-
Start Pi and ask the agent to load the
|
|
46
|
-
|
|
47
|
-
Run `/chrome-devtools` to review
|
|
48
|
-
|
|
49
|
+
Start Pi and ask the agent to load the browser capability needed for the task.
|
|
50
|
+
By default, the extension tries `http://127.0.0.1:9222` and launches an isolated local Chromium-family browser if that endpoint is unavailable.
|
|
51
|
+
Run `/chrome-devtools` to review status, settings, help, and available tools.
|
|
52
|
+
WebMCP remains disabled until you explicitly enable it.
|
|
49
53
|
|
|
50
54
|
## 🌐 Browser setup
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
Configure the canonical user file at `${PI_CODING_AGENT_DIR:-~/.pi/agent}/pi-chrome-devtools.json`:
|
|
57
|
-
|
|
58
|
-
```json
|
|
59
|
-
{
|
|
60
|
-
"browser": {
|
|
61
|
-
"endpoint": "http://127.0.0.1:9222",
|
|
62
|
-
"autoLaunch": true,
|
|
63
|
-
"executablePath": "/absolute/path/to/chromium"
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
`browser.endpoint` must be an HTTP origin with an explicit port and no credentials, path, query, or fragment.
|
|
69
|
-
Omitting it keeps attach-first behavior on `127.0.0.1:9222` and lets a managed launch use Chrome's dynamic DevTools port mode (`--remote-debugging-port=0`).
|
|
70
|
-
Explicitly saving an endpoint pins managed launches to that port.
|
|
71
|
-
`browser.autoLaunch` defaults to `true`.
|
|
72
|
-
`browser.executablePath` is optional and must be an absolute path; when absent, normal browser discovery applies.
|
|
73
|
-
|
|
74
|
-
The configured endpoint must expose the standard CDP HTTP discovery routes such as `/json/version` and `/json/list`.
|
|
75
|
-
Chrome's newer built-in permission flow can listen on port `9222` while returning `404` from those routes; setting the same HTTP origin does not by itself make that flow compatible.
|
|
56
|
+
By default, the extension attaches to `http://127.0.0.1:9222` or launches an isolated local browser on first use.
|
|
57
|
+
It never closes an external browser.
|
|
58
|
+
Use `/chrome-devtools` → **Browser settings** to change the endpoint, auto-launch policy, or executable.
|
|
76
59
|
|
|
77
|
-
|
|
60
|
+
Read the [browser setup reference](./docs/browser-setup.md) for endpoint requirements, executable discovery, unpacked extensions, manual launch, and deprecated environment overrides.
|
|
61
|
+
Manual settings edits apply after `/reload` or session replacement.
|
|
78
62
|
|
|
79
63
|
> [!WARNING]
|
|
80
|
-
>
|
|
81
|
-
>
|
|
82
|
-
>
|
|
83
|
-
|
|
84
|
-
Add trusted unpacked-extension paths to the same canonical user file:
|
|
85
|
-
|
|
86
|
-
```json
|
|
87
|
-
{
|
|
88
|
-
"browser": {
|
|
89
|
-
"executablePath": "/absolute/path/to/chrome-for-testing",
|
|
90
|
-
"extensionPaths": [
|
|
91
|
-
"/absolute/path/to/unpacked-extension-one",
|
|
92
|
-
"/absolute/path/to/unpacked-extension-two"
|
|
93
|
-
]
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
Every user-file path must be absolute.
|
|
99
|
-
Each extension path must resolve to a directory containing a valid `manifest.json` and cannot contain a comma because Chrome uses commas to separate multiple startup paths.
|
|
100
|
-
For extension-configured sessions, `executablePath` must identify Chrome for Testing or Chromium.
|
|
101
|
-
Branded Google Chrome is rejected because tested releases can silently ignore unpacked-extension startup flags.
|
|
102
|
-
|
|
103
|
-
A trusted project can replace the user extension list in `<workspace>/.pi/pi-chrome-devtools.json`.
|
|
104
|
-
Relative paths resolve from the workspace (`ctx.cwd`):
|
|
105
|
-
|
|
106
|
-
```json
|
|
107
|
-
{
|
|
108
|
-
"browser": {
|
|
109
|
-
"extensionPaths": ["./extension"]
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Project `extensionPaths` replace, rather than append to, the user array.
|
|
115
|
-
A project file cannot override `browser.endpoint`, `browser.autoLaunch`, or `browser.executablePath`; browser connection settings remain machine-owned user configuration.
|
|
116
|
-
Effective precedence is defaults, user settings, trusted project extension paths, then deprecated environment overrides.
|
|
117
|
-
No new environment variable is required.
|
|
118
|
-
|
|
119
|
-
When `extensionPaths` is non-empty, the extension skips attach-first behavior and starts an isolated, extension-owned managed browser with `--disable-extensions-except` and `--load-extension`.
|
|
120
|
-
It fails before spawning when the endpoint is remote, auto-launch is disabled, an explicit port is occupied, the executable is missing, or the browser product is unsupported.
|
|
121
|
-
It never adds extensions to, modifies, restarts, or closes an external browser.
|
|
122
|
-
|
|
123
|
-
Settings are loaded on session start.
|
|
124
|
-
After editing JSON, use `/reload` or replace the session; the old managed browser is closed before the new configuration is applied.
|
|
125
|
-
Missing files preserve the existing no-extension behavior.
|
|
126
|
-
Invalid JSON, invalid browser values, and missing manifests are left unchanged and ignored with an actionable warning.
|
|
64
|
+
> Unpacked extensions execute privileged browser code; load only trusted code.
|
|
65
|
+
> They require an extension-owned Chrome for Testing or Chromium process.
|
|
66
|
+
> Trusted project settings may replace only the extension-path list, not machine-owned connection settings.
|
|
127
67
|
|
|
128
68
|
### Experimental WebMCP
|
|
129
69
|
|
|
130
70
|
> [!WARNING]
|
|
131
|
-
> WebMCP
|
|
132
|
-
> Page
|
|
133
|
-
> Every call requires observable confirmation, including tools that claim to be read-only.
|
|
134
|
-
|
|
135
|
-
Enable WebMCP only in the canonical user settings file:
|
|
136
|
-
|
|
137
|
-
```json
|
|
138
|
-
{
|
|
139
|
-
"webmcp": {
|
|
140
|
-
"enabled": true
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
A project `pi-chrome-devtools.json` cannot enable WebMCP or weaken confirmation policy.
|
|
146
|
-
The settings menu labels WebMCP as experimental, persists the user-owned boolean atomically, and aborts active WebMCP work before disablement or browser replacement.
|
|
147
|
-
The two gateway tools remain unavailable while the gate is disabled even if an older `tools` array contains their names.
|
|
148
|
-
After enabling the gate, choose whether each gateway is available through `/chrome-devtools tools` or the main menu.
|
|
149
|
-
|
|
150
|
-
WebMCP requires a Chrome build whose `/json/protocol` exposes the experimental `WebMCP` domain.
|
|
151
|
-
Origin-trial sites must meet Chrome's Origin Trial, origin isolation, Permissions Policy, authentication, and browser feature requirements.
|
|
152
|
-
For local pages outside an Origin Trial, open `chrome://flags/#enable-webmcp-testing`, enable **WebMCP for testing**, and relaunch a compatible Chrome build.
|
|
153
|
-
The extension does not automatically add testing flags to a managed browser.
|
|
154
|
-
|
|
155
|
-
`chrome_devtools_webmcp_list_tools` opens an operation-scoped page CDP session, lists frame-aware page tools, and returns bounded metadata with a deterministic schema-and-annotation digest.
|
|
156
|
-
`chrome_devtools_webmcp_call_tool` re-discovers the exact page, document loader, frame, origin, tool, schema, annotations, and session generation before invocation and again after confirmation.
|
|
157
|
-
The call gateway rejects print and JSON modes because they cannot provide observable confirmation.
|
|
158
|
-
TUI and RPC modes use Pi's standard confirmation dialog.
|
|
159
|
-
Cancellation is forwarded to Chrome through `WebMCP.cancelInvocation` after Chrome returns an invocation ID.
|
|
160
|
-
|
|
161
|
-
Page URLs, origins, names, descriptions, schemas, errors, and outputs are untrusted.
|
|
162
|
-
Displayed text strips terminal controls and bidirectional overrides, accepted JSON has explicit byte, depth, and collection limits, and model-visible output is capped at 50 KB or 2,000 lines.
|
|
163
|
-
CDP text messages are capped at 8 MB before JSON parsing.
|
|
164
|
-
Page-controlled `pattern` and `patternProperties` schemas and schemas exceeding 128 combinator or dependent-schema branches are rejected because they cannot be evaluated safely on Pi's main thread.
|
|
165
|
-
Annotations are descriptive hints only and never authorize a call.
|
|
166
|
-
WebMCP is not backend MCP, generic browser automation, or a way to bypass browser policy.
|
|
167
|
-
|
|
168
|
-
If listing reports that the WebMCP domain is unavailable, update Chrome and verify `/json/protocol` contains `WebMCP`.
|
|
169
|
-
If a page lists no tools, verify that the site participates in the Origin Trial or that **WebMCP for testing** is enabled for local development.
|
|
170
|
-
If a call reports a stale identity, list tools again after navigation, reload, frame changes, tool registration changes, settings changes, or browser replacement.
|
|
171
|
-
Attached everyday browser profiles receive a stronger confirmation warning than isolated managed profiles.
|
|
71
|
+
> WebMCP is experimental, disabled by default, and subject to Chrome protocol changes.
|
|
72
|
+
> Page tools use the visible page's current authentication and require confirmation on every call.
|
|
172
73
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
They still take precedence over JSON, but every session that sees one emits a deprecation warning.
|
|
177
|
-
Move their values to `browser.endpoint`, `browser.autoLaunch`, and `browser.executablePath`; the variables will be removed in a future version.
|
|
178
|
-
|
|
179
|
-
Without unpacked extensions, browser discovery still checks platform-specific Chrome, Chromium, Brave, and Microsoft Edge candidates.
|
|
180
|
-
Manual launch remains available when no unpacked extensions are configured:
|
|
181
|
-
|
|
182
|
-
```bash
|
|
183
|
-
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/pi-chrome-devtools
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
On session shutdown, the extension terminates only browser processes it started and best-effort removes their temporary profiles.
|
|
187
|
-
It never closes user-started browsers or remote endpoints.
|
|
74
|
+
Enable `webmcp.enabled` only in user settings, then choose which gateway tools are available through `/chrome-devtools tools`.
|
|
75
|
+
Project settings cannot enable WebMCP or weaken confirmation.
|
|
76
|
+
See [WebMCP setup and troubleshooting](./docs/browser-setup.md#experimental-webmcp) for compatible Chrome builds, browser flags, schema limits, and stale-page recovery.
|
|
188
77
|
|
|
189
78
|
## 🛠️ Tools
|
|
190
79
|
|
|
@@ -199,30 +88,22 @@ It never closes user-started browsers or remote endpoints.
|
|
|
199
88
|
|
|
200
89
|
### Tool exposure
|
|
201
90
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
On a model/provider with native deferred-tool support, only `chrome_devtools_load` starts active for this extension.
|
|
205
|
-
|
|
91
|
+
The extension registers eight tools: one loader, five stable DevTools capabilities, and two fixed experimental WebMCP gateways.
|
|
92
|
+
With native deferred-tool support, only `chrome_devtools_load` starts active.
|
|
206
93
|
The loader accepts a task-oriented `query`, matches it against the five stable capabilities plus enabled WebMCP gateways, and adds matching available tools without removing any active Pi tool.
|
|
207
|
-
|
|
208
94
|
Loaded capability tools remain active for the rest of the session unless the user makes them unavailable through `/chrome-devtools`.
|
|
209
95
|
|
|
210
96
|
Pi uses native deferred tool references on compatible Anthropic models, native additional-tools or tool-search loading on compatible OpenAI and Codex Responses models, and native Kimi loading on compatible OpenAI Chat Completions models.
|
|
211
|
-
|
|
212
97
|
Kimi-compatible models declare `compat.deferredToolsMode: "kimi"` in Pi's model metadata.
|
|
213
|
-
|
|
214
98
|
`azure-openai-responses` remains eager because Pi's Azure adapter does not implement native deferred tool-search serialization.
|
|
215
99
|
|
|
216
100
|
When the selected model/provider lacks native deferred support, the extension activates every capability allowed by settings before the next model request instead of using Pi's cache-invalidating lazy-loading fallback.
|
|
217
|
-
|
|
218
101
|
After a session enters eager exposure, it stays eager across later model switches to avoid removing tool definitions within that session.
|
|
219
|
-
|
|
220
102
|
The capability tools omit active-only prompt snippets so native deferred loading does not rebuild the system-prompt prefix.
|
|
221
103
|
|
|
222
104
|
The saved `tools` array controls which capabilities the extension may expose.
|
|
223
|
-
The `webmcp.enabled` gate
|
|
105
|
+
The `webmcp.enabled` gate takes precedence, so persisted WebMCP names cannot bypass a disabled gate.
|
|
224
106
|
Page-provided tool definitions appear only in list results and never alter Pi's provider-visible tool definitions.
|
|
225
|
-
|
|
226
107
|
An empty array leaves the loader active but makes every browser capability unavailable.
|
|
227
108
|
|
|
228
109
|
### Screenshot files
|
|
@@ -253,55 +134,25 @@ If the model cannot inspect the inline image, ask it to read the saved path, for
|
|
|
253
134
|
|
|
254
135
|
## 💬 Commands
|
|
255
136
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
-
|
|
264
|
-
-
|
|
265
|
-
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
Direct subcommands are also available:
|
|
277
|
-
|
|
278
|
-
```text
|
|
279
|
-
/chrome-devtools help
|
|
280
|
-
/chrome-devtools quickstart
|
|
281
|
-
/chrome-devtools status
|
|
282
|
-
/chrome-devtools settings
|
|
283
|
-
/chrome-devtools tools
|
|
284
|
-
/chrome-devtools toggle
|
|
285
|
-
/chrome-devtools enable
|
|
286
|
-
/chrome-devtools disable
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
Compatibility aliases remain available: `toggle` and `select` mean `tools`, `on` means `enable`, and `off` means `disable`.
|
|
290
|
-
|
|
291
|
-
- `help` shows command usage.
|
|
292
|
-
- `quickstart` shows the configured CDP endpoint, endpoint source, auto-launch mode, browser candidates, last launch attempt, and launch hints.
|
|
293
|
-
- `status` shows available and loaded capability counts, loader state, the persisted catalog, settings file path, endpoint source, launch mode, last launch attempt, and active non-Chrome tool count.
|
|
294
|
-
- `settings` opens the same immediate-save browser settings flow used by the menu.
|
|
295
|
-
- `tools` opens the same staged, width-safe availability and review flow used by the menu.
|
|
296
|
-
- `toggle` and `select` are compatibility aliases for `tools`.
|
|
297
|
-
- `enable` makes all currently gated capability tools available and follows the current native-deferred or eager exposure mode; `on` is a compatibility alias.
|
|
298
|
-
- `disable` makes all capability tools unavailable and saves the empty catalog; `off` is a compatibility alias.
|
|
299
|
-
The slash command and `chrome_devtools_load` remain available.
|
|
300
|
-
|
|
301
|
-
The menu, `settings`, `tools`, `help`, `quickstart`, and `status` require TUI or RPC mode so their result is observable.
|
|
302
|
-
TUI uses keyboard navigation and injected Pi keybindings; RPC receives equivalent standard dialogs.
|
|
303
|
-
In print and JSON modes, interactive and informational routes reject explicitly instead of silently opening unavailable UI.
|
|
304
|
-
The immediate `enable`/`disable` routes remain available for deterministic non-interactive use.
|
|
137
|
+
| Command | Purpose |
|
|
138
|
+
| --- | --- |
|
|
139
|
+
| `/chrome-devtools` | Manage browser-tool availability and browser settings. |
|
|
140
|
+
| `/chrome-devtools help` | Show command usage. |
|
|
141
|
+
| `/chrome-devtools quickstart` | Show the CDP endpoint, launch candidates, and setup hints. |
|
|
142
|
+
| `/chrome-devtools status` | Inspect tools, settings sources, and the last browser launch without probing or starting Chrome. |
|
|
143
|
+
| `/chrome-devtools settings` | Change browser settings; successful edits save immediately. |
|
|
144
|
+
| `/chrome-devtools tools` (aliases: `toggle`, `select`) | Stage tool availability, review the result, and apply it. |
|
|
145
|
+
| `/chrome-devtools enable` (alias: `on`) | Immediately make all currently gated capabilities available and save the selection. |
|
|
146
|
+
| `/chrome-devtools disable` (alias: `off`) | Immediately make all capabilities unavailable and save the empty selection. |
|
|
147
|
+
|
|
148
|
+
All routes support TUI and RPC and reject unknown or trailing arguments.
|
|
149
|
+
Only `enable` and `disable` also support print and JSON modes.
|
|
150
|
+
Disabling capabilities leaves the slash command and `chrome_devtools_load` available; see [Tool exposure](#tool-exposure).
|
|
151
|
+
|
|
152
|
+
Menu tool changes require **Apply tool changes**; cancellation discards the unconfirmed draft.
|
|
153
|
+
Failed apply leaves previous tool availability and settings intact and retains the draft for retry.
|
|
154
|
+
Browser settings instead save immediately, and closing the flow does not undo them.
|
|
155
|
+
See [Browser setup](./docs/browser-setup.md) for prerequisites and environment-override precedence, and [Experimental WebMCP](#experimental-webmcp) before enabling its gateways.
|
|
305
156
|
|
|
306
157
|
## ⚙️ Settings
|
|
307
158
|
|
|
@@ -311,6 +162,18 @@ The available capability names are saved to:
|
|
|
311
162
|
${PI_CODING_AGENT_DIR:-~/.pi/agent}/pi-chrome-devtools.json
|
|
312
163
|
```
|
|
313
164
|
|
|
165
|
+
Use **Browser settings** for connection preferences or **Choose available browser tools…** for tool availability.
|
|
166
|
+
For example, this partial document attaches to a user-started browser without launching another:
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"browser": {
|
|
171
|
+
"endpoint": "http://127.0.0.1:9222",
|
|
172
|
+
"autoLaunch": false
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
314
177
|
The same file owns `browser.endpoint`, `browser.autoLaunch`, `browser.executablePath`, `browser.extensionPaths`, and user-only `webmcp.enabled`.
|
|
315
178
|
Browser connection fields and `webmcp.enabled` are machine-owned user settings; trusted project files may replace only `browser.extensionPaths`.
|
|
316
179
|
Confirmed menu changes apply before the next browser connection and close only an extension-owned managed browser.
|
|
@@ -328,6 +191,18 @@ The first subsequent settings save writes the canonical file.
|
|
|
328
191
|
If both files exist, `pi-chrome-devtools.json` wins and the legacy file is ignored.
|
|
329
192
|
The legacy filename is deprecated and will be removed in a future major release.
|
|
330
193
|
|
|
194
|
+
## 🔒 Security and privacy
|
|
195
|
+
|
|
196
|
+
A CDP connection can inspect and change browser content, execute JavaScript, and access the selected browser profile's authenticated pages.
|
|
197
|
+
Connect only to trusted endpoints and profiles.
|
|
198
|
+
|
|
199
|
+
The extension never closes an external browser.
|
|
200
|
+
It closes only managed browser processes that it started and removes their temporary profiles on a best-effort basis.
|
|
201
|
+
|
|
202
|
+
Unpacked extensions run privileged browser code and are loaded only into an isolated managed browser after explicit configuration.
|
|
203
|
+
WebMCP page tools use the visible page's authentication and require confirmation before every call.
|
|
204
|
+
Screenshot output is restricted to the current working directory or OS temporary directory as described above.
|
|
205
|
+
|
|
331
206
|
## 🧠 Use cases
|
|
332
207
|
|
|
333
208
|
- Debug front-end applications with an AI coding agent.
|
|
@@ -338,36 +213,19 @@ The legacy filename is deprecated and will be removed in a future major release.
|
|
|
338
213
|
|
|
339
214
|
## 🗂️ Package layout
|
|
340
215
|
|
|
341
|
-
```
|
|
216
|
+
```text
|
|
342
217
|
packages/pi-chrome-devtools/
|
|
343
|
-
├──
|
|
344
|
-
├──
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
├──
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
│ ├── webmcp/ # Lazy CDP protocol, discovery, policy, and invocation implementation
|
|
352
|
-
│ └── *.ts # Package-local browser, CDP, tool, and storage modules
|
|
353
|
-
├── README.md
|
|
354
|
-
├── LICENSE
|
|
355
|
-
├── tsconfig.json
|
|
356
|
-
└── package.json
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
`index.ts` is the Pi entrypoint and forwards to `chrome-devtools.ts`; the other source modules are internal.
|
|
360
|
-
The package exposes its Pi extension through `package.json`:
|
|
361
|
-
|
|
362
|
-
```json
|
|
363
|
-
{
|
|
364
|
-
"pi": {
|
|
365
|
-
"extensions": ["./dist/index.ts"]
|
|
366
|
-
}
|
|
367
|
-
}
|
|
218
|
+
├── src/ # Authoritative implementation and helpers
|
|
219
|
+
│ ├── index.ts # Thin Pi entrypoint
|
|
220
|
+
│ └── chrome-devtools.ts # Browser tools and command orchestration
|
|
221
|
+
├── dist/ # Generated Jiti runtime
|
|
222
|
+
├── scripts/build-runtime.mjs # Runtime builder
|
|
223
|
+
├── docs/ # Published reference documentation
|
|
224
|
+
├── reference/webmcp/ # Repository-only compatibility prototype
|
|
225
|
+
└── test/ # Behavior and lifecycle coverage
|
|
368
226
|
```
|
|
369
227
|
|
|
370
|
-
The generated runtime is built from
|
|
228
|
+
The generated runtime is built from `src/index.ts` and does not import back into `src`.
|
|
371
229
|
|
|
372
230
|
## 🔎 Keywords
|
|
373
231
|
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
configuredChromeDevtoolsTools,
|
|
6
6
|
sanitizeChromeDevtoolsDisplay,
|
|
7
7
|
setChromeDevtoolsSessionOwner
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-LLXOCRNF.js";
|
|
9
9
|
import {
|
|
10
10
|
applyRuntimeBrowserSettings,
|
|
11
11
|
applyRuntimeWebMcpSetting,
|
|
@@ -339,4 +339,4 @@ function formatError(error) {
|
|
|
339
339
|
export {
|
|
340
340
|
showChromeDevtoolsBrowserSettings
|
|
341
341
|
};
|
|
342
|
-
//# sourceMappingURL=browser-settings-menu-
|
|
342
|
+
//# sourceMappingURL=browser-settings-menu-IMB6HXSU.js.map
|
|
@@ -192,8 +192,37 @@ function unique(values) {
|
|
|
192
192
|
return [...new Set(values)];
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
// src/display.ts
|
|
196
|
+
var MAX_SANITIZER_INPUT_CODE_UNITS = 5e4;
|
|
197
|
+
var graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
198
|
+
function sanitizeChromeDevtoolsDisplay(value, maxCharacters = 5e4) {
|
|
199
|
+
const inputWasTruncated = value.length > MAX_SANITIZER_INPUT_CODE_UNITS;
|
|
200
|
+
const boundedInput = inputWasTruncated ? truncateAtGraphemeBoundary(value, MAX_SANITIZER_INPUT_CODE_UNITS) : value;
|
|
201
|
+
const normalizedLineEndings = boundedInput.replace(/\r\n/g, "\n");
|
|
202
|
+
const sanitized = Array.from(normalizedLineEndings, (character) => {
|
|
203
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
204
|
+
const unsafeControl = codePoint >= 0 && codePoint <= 8 || codePoint >= 11 && codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
|
|
205
|
+
const unsafeBidi = codePoint >= 8234 && codePoint <= 8238 || codePoint >= 8294 && codePoint <= 8297;
|
|
206
|
+
const loneSurrogate = character.length === 1 && codePoint >= 55296 && codePoint <= 57343;
|
|
207
|
+
return unsafeControl || unsafeBidi || loneSurrogate ? "\uFFFD" : character;
|
|
208
|
+
}).join("");
|
|
209
|
+
const outputLimit = Math.min(maxCharacters, MAX_SANITIZER_INPUT_CODE_UNITS);
|
|
210
|
+
if (!inputWasTruncated && sanitized.length <= outputLimit) return sanitized;
|
|
211
|
+
return `${truncateAtGraphemeBoundary(sanitized, Math.max(0, outputLimit - 1))}\u2026`;
|
|
212
|
+
}
|
|
213
|
+
function truncateAtGraphemeBoundary(value, maxCodeUnits) {
|
|
214
|
+
if (value.length <= maxCodeUnits) return value;
|
|
215
|
+
const boundedLookahead = value.slice(0, Math.max(0, maxCodeUnits) + 2);
|
|
216
|
+
let safeEnd = 0;
|
|
217
|
+
for (const { index, segment } of graphemeSegmenter.segment(boundedLookahead)) {
|
|
218
|
+
const segmentEnd = index + segment.length;
|
|
219
|
+
if (segmentEnd > maxCodeUnits) break;
|
|
220
|
+
safeEnd = segmentEnd;
|
|
221
|
+
}
|
|
222
|
+
return value.slice(0, safeEnd);
|
|
223
|
+
}
|
|
224
|
+
|
|
195
225
|
// src/tool-selector.ts
|
|
196
|
-
import { stripVTControlCharacters } from "node:util";
|
|
197
226
|
function unique2(values) {
|
|
198
227
|
return Array.from(new Set(values));
|
|
199
228
|
}
|
|
@@ -367,19 +396,6 @@ function buildSettingsSetupMessage(owner) {
|
|
|
367
396
|
].join("\n")
|
|
368
397
|
);
|
|
369
398
|
}
|
|
370
|
-
function sanitizeChromeDevtoolsDisplay(value, maxCharacters = 5e4) {
|
|
371
|
-
const withoutBidi = stripVTControlCharacters(value).replace(
|
|
372
|
-
/[\u202a-\u202e\u2066-\u2069]/gu,
|
|
373
|
-
"\uFFFD"
|
|
374
|
-
);
|
|
375
|
-
const sanitized = Array.from(withoutBidi, (character) => {
|
|
376
|
-
const codePoint = character.codePointAt(0) ?? 0;
|
|
377
|
-
const unsafeControl = codePoint >= 0 && codePoint <= 8 || codePoint >= 11 && codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
|
|
378
|
-
return unsafeControl ? "\uFFFD" : character;
|
|
379
|
-
}).join("");
|
|
380
|
-
if (sanitized.length <= maxCharacters) return sanitized;
|
|
381
|
-
return `${sanitized.slice(0, Math.max(0, maxCharacters - 1))}\u2026`;
|
|
382
|
-
}
|
|
383
399
|
function browserSettingsStatusLines(owner) {
|
|
384
400
|
const browser = browserSettingsForOwner(owner);
|
|
385
401
|
const extensionPaths = browser.extensionPaths;
|
|
@@ -456,14 +472,14 @@ export {
|
|
|
456
472
|
availableChromeDevtoolsTools,
|
|
457
473
|
configuredChromeDevtoolsTools,
|
|
458
474
|
createChromeDevtoolsLoadTool,
|
|
475
|
+
sanitizeChromeDevtoolsDisplay,
|
|
459
476
|
updateChromeDevtoolsTools,
|
|
460
477
|
setSelectedChromeDevtoolsTools,
|
|
461
478
|
waitForChromeDevtoolsSettings,
|
|
462
479
|
buildToolStatusMessage,
|
|
463
480
|
buildQuickstartMessage,
|
|
464
481
|
buildBrowserStatusMessage,
|
|
465
|
-
sanitizeChromeDevtoolsDisplay,
|
|
466
482
|
buildCommandGuide,
|
|
467
483
|
allChromeDevtoolsTools
|
|
468
484
|
};
|
|
469
|
-
//# sourceMappingURL=chunk-
|
|
485
|
+
//# sourceMappingURL=chunk-LLXOCRNF.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lazy-tools.ts", "../../src/display.ts", "../../src/tool-selector.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n\tdefineTool,\n\ttype ExtensionAPI,\n\ttype ExtensionContext,\n} from \"@earendil-works/pi-coding-agent\";\nimport { Type } from \"typebox\";\nimport { webMcpEnabled } from \"./runtime.js\";\nimport {\n\tCHROME_DEVTOOLS_TOOL_NAMES,\n\ttype ChromeDevToolsToolName,\n\tisWebMcpToolName,\n} from \"./tool-names.js\";\n\nexport const CHROME_DEVTOOLS_LOAD_TOOL_NAME = \"chrome_devtools_load\";\n\nconst AVAILABLE_TOOLS_STORE = Symbol.for(\"@narumitw/pi-chrome-devtools.available-tools-store\");\ntype ChromeDevtoolsGlobal = typeof globalThis & {\n\t[AVAILABLE_TOOLS_STORE]?: WeakMap<ExtensionAPI, Set<ChromeDevToolsToolName>>;\n};\nconst sharedGlobal = globalThis as ChromeDevtoolsGlobal;\nconst existingAvailableToolsStore = sharedGlobal[AVAILABLE_TOOLS_STORE];\nconst availableToolsByApi =\n\texistingAvailableToolsStore ?? new WeakMap<ExtensionAPI, Set<ChromeDevToolsToolName>>();\nif (!existingAvailableToolsStore) sharedGlobal[AVAILABLE_TOOLS_STORE] = availableToolsByApi;\nconst lazyExposureByApi = new WeakMap<ExtensionAPI, boolean>();\nconst sessionOwnerByApi = new WeakMap<ExtensionAPI, object>();\n\nconst SEARCH_TEXT: Record<ChromeDevToolsToolName, string> = {\n\tchrome_devtools_list_pages: \"list open inspectable chrome browser pages tabs targets\",\n\tchrome_devtools_select_page: \"select choose active chrome browser page tab target\",\n\tchrome_devtools_navigate: \"navigate open create chrome browser page url website\",\n\tchrome_devtools_evaluate: \"evaluate run javascript expression dom inspect chrome browser page\",\n\tchrome_devtools_screenshot: \"capture screenshot png image visual chrome browser page\",\n\tchrome_devtools_webmcp_list_tools:\n\t\t\"list discover page provided website webmcp tools capabilities experimental\",\n\tchrome_devtools_webmcp_call_tool:\n\t\t\"call invoke page provided website webmcp tool confirmation experimental\",\n};\n\nexport function setChromeDevtoolsSessionOwner(pi: ExtensionAPI, owner: object) {\n\tsessionOwnerByApi.set(pi, owner);\n}\n\nexport function initializeAvailableChromeDevtoolsTools(pi: ExtensionAPI) {\n\tif (availableToolsByApi.has(pi)) return;\n\tconst activeTools = new Set(pi.getActiveTools());\n\tsetAvailableTools(\n\t\tpi,\n\t\tCHROME_DEVTOOLS_TOOL_NAMES.filter((name) => activeTools.has(name)),\n\t);\n}\n\nexport function configureChromeDevtoolsToolExposure(\n\tpi: ExtensionAPI,\n\tavailableTools: readonly ChromeDevToolsToolName[],\n\tmodel?: ExtensionContext[\"model\"],\n) {\n\tsetAvailableTools(pi, availableTools);\n\tconst available = effectiveAvailableTools(pi);\n\tconst lazyExposure = supportsNativeDeferredToolLoading(model);\n\tlazyExposureByApi.set(pi, lazyExposure);\n\tconst exposedTools = lazyExposure\n\t\t? []\n\t\t: CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));\n\tconst nonCapabilityTools = pi\n\t\t.getActiveTools()\n\t\t.filter((name) => !CHROME_DEVTOOLS_TOOL_NAMES.includes(name as ChromeDevToolsToolName));\n\tpi.setActiveTools(\n\t\tunique([...nonCapabilityTools, CHROME_DEVTOOLS_LOAD_TOOL_NAME, ...exposedTools]),\n\t);\n}\n\nexport function requireEagerChromeDevtoolsToolExposure(pi: ExtensionAPI) {\n\tlazyExposureByApi.set(pi, false);\n\tconst active = pi.getActiveTools();\n\tconst available = availableChromeDevtoolsTools(pi);\n\tpi.setActiveTools(unique([...active, CHROME_DEVTOOLS_LOAD_TOOL_NAME, ...available]));\n}\n\nexport function applyAvailableChromeDevtoolsTools(\n\tpi: ExtensionAPI,\n\tavailableTools: readonly ChromeDevToolsToolName[],\n) {\n\tsetAvailableTools(pi, availableTools);\n\tconst available = effectiveAvailableTools(pi);\n\tconst lazyExposure = lazyExposureByApi.get(pi) === true;\n\tconst active = pi\n\t\t.getActiveTools()\n\t\t.filter(\n\t\t\t(name) =>\n\t\t\t\t!CHROME_DEVTOOLS_TOOL_NAMES.includes(name as ChromeDevToolsToolName) ||\n\t\t\t\t(lazyExposure && available.has(name as ChromeDevToolsToolName)),\n\t\t);\n\tconst eagerTools = lazyExposure\n\t\t? []\n\t\t: CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));\n\tpi.setActiveTools(unique([...active, CHROME_DEVTOOLS_LOAD_TOOL_NAME, ...eagerTools]));\n}\n\nexport function chromeDevtoolsToolExposureMode(pi: ExtensionAPI) {\n\treturn lazyExposureByApi.get(pi) === true ? \"native deferred\" : \"eager\";\n}\n\nexport function supportsNativeDeferredToolLoading(model: ExtensionContext[\"model\"]): boolean {\n\tif (!model) return false;\n\tif (model.api === \"anthropic-messages\") {\n\t\tconst configured = compatBoolean(model.compat, \"supportsToolReferences\");\n\t\tif (configured !== undefined) return configured;\n\t\tif (model.provider !== \"anthropic\" || model.id.includes(\"haiku\")) return false;\n\t\tconst version = model.id.match(/^claude-(?:opus|sonnet|fable)-(\\d+)(?:-(\\d+))?(?:-|$)/);\n\t\tif (!version) return false;\n\t\tconst major = Number(version[1]);\n\t\tconst minor = version[2] && version[2].length < 8 ? Number(version[2]) : 0;\n\t\treturn major > 4 || (major === 4 && minor >= 5);\n\t}\n\tif (model.api === \"openai-completions\") {\n\t\treturn compatString(model.compat, \"deferredToolsMode\") === \"kimi\";\n\t}\n\tif (model.api === \"openai-responses\" || model.api === \"openai-codex-responses\") {\n\t\treturn (\n\t\t\tcompatBoolean(model.compat, \"supportsAdditionalTools\") === true ||\n\t\t\tcompatBoolean(model.compat, \"supportsToolSearch\") === true\n\t\t);\n\t}\n\treturn false;\n}\n\nexport function availableChromeDevtoolsTools(pi: ExtensionAPI) {\n\tconst available = effectiveAvailableTools(pi);\n\treturn CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));\n}\n\nexport function configuredChromeDevtoolsTools(pi: ExtensionAPI) {\n\tconst available = availableToolsByApi.get(pi) ?? new Set();\n\treturn CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));\n}\n\nexport function createChromeDevtoolsLoadTool(pi: ExtensionAPI) {\n\treturn defineTool({\n\t\tname: CHROME_DEVTOOLS_LOAD_TOOL_NAME,\n\t\tlabel: \"Chrome DevTools: Load Tools\",\n\t\tdescription:\n\t\t\t\"Find and enable Chrome DevTools browser tools relevant to a task. Loaded tools remain available for the session.\",\n\t\tpromptSnippet: \"Load Chrome DevTools browser capabilities on demand\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use chrome_devtools_load when a task requires inspecting or controlling a Chrome browser and the needed chrome_devtools_* capability is not active.\",\n\t\t],\n\t\tparameters: Type.Object({\n\t\t\tquery: Type.String({\n\t\t\t\tdescription: \"Browser capability or task to find tools for.\",\n\t\t\t\tmaxLength: 500,\n\t\t\t}),\n\t\t\tlimit: Type.Optional(\n\t\t\t\tType.Integer({\n\t\t\t\t\tdescription: \"Maximum tools to load. Defaults to 3.\",\n\t\t\t\t\tminimum: 1,\n\t\t\t\t\tmaximum: 5,\n\t\t\t\t}),\n\t\t\t),\n\t\t}),\n\t\tasync execute(_toolCallId, params, signal, _onUpdate, ctx) {\n\t\t\tsignal?.throwIfAborted();\n\t\t\tsetChromeDevtoolsSessionOwner(pi, ctx.sessionManager);\n\t\t\tconst available = new Set(availableChromeDevtoolsTools(pi));\n\t\t\tconst matches = matchChromeDevtoolsTools(params.query, params.limit ?? 3, available);\n\t\t\tconst active = pi.getActiveTools();\n\t\t\tconst activeSet = new Set(active);\n\t\t\tconst added = matches.filter((name) => !activeSet.has(name));\n\t\t\tif (added.length > 0) {\n\t\t\t\tpi.setActiveTools(unique([...active, ...added]));\n\t\t\t}\n\n\t\t\tconst text =\n\t\t\t\tmatches.length === 0\n\t\t\t\t\t? \"No available Chrome DevTools tools matched the query.\"\n\t\t\t\t\t: added.length > 0\n\t\t\t\t\t\t? `Loaded Chrome DevTools tools: ${added.join(\", \")}`\n\t\t\t\t\t\t: `Matching Chrome DevTools tools are already loaded: ${matches.join(\", \")}`;\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text }],\n\t\t\t\tdetails: { matches, added },\n\t\t\t};\n\t\t},\n\t});\n}\n\nfunction matchChromeDevtoolsTools(\n\tquery: string,\n\tlimit: number,\n\tavailable: ReadonlySet<ChromeDevToolsToolName>,\n) {\n\tconst terms = query\n\t\t.toLowerCase()\n\t\t.split(/[^a-z0-9]+/)\n\t\t.filter((term) => term.length >= 2);\n\tif (terms.length === 0) return [];\n\treturn CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name))\n\t\t.map((name, index) => ({\n\t\t\tname,\n\t\t\tindex,\n\t\t\tscore: terms.reduce((score, term) => score + (SEARCH_TEXT[name].includes(term) ? 1 : 0), 0),\n\t\t}))\n\t\t.filter((match) => match.score > 0)\n\t\t.sort((left, right) => right.score - left.score || left.index - right.index)\n\t\t.slice(0, limit)\n\t\t.map((match) => match.name);\n}\n\nfunction setAvailableTools(pi: ExtensionAPI, availableTools: readonly ChromeDevToolsToolName[]) {\n\tconst available = new Set(availableTools);\n\tavailableToolsByApi.set(pi, available);\n\treturn available;\n}\n\nfunction effectiveAvailableTools(pi: ExtensionAPI) {\n\tconst configured = availableToolsByApi.get(pi) ?? new Set();\n\tconst owner = sessionOwnerByApi.get(pi);\n\tconst enabled = owner !== undefined && webMcpEnabled(owner);\n\treturn new Set(\n\t\tCHROME_DEVTOOLS_TOOL_NAMES.filter(\n\t\t\t(name) => configured.has(name) && (enabled || !isWebMcpToolName(name)),\n\t\t),\n\t);\n}\n\nfunction compatBoolean(value: unknown, key: string) {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return undefined;\n\tconst record = value as Record<string, unknown>;\n\treturn typeof record[key] === \"boolean\" ? record[key] : undefined;\n}\n\nfunction compatString(value: unknown, key: string) {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return undefined;\n\tconst record = value as Record<string, unknown>;\n\treturn typeof record[key] === \"string\" ? record[key] : undefined;\n}\n\nfunction unique(values: readonly string[]) {\n\treturn [...new Set(values)];\n}\n", "const MAX_SANITIZER_INPUT_CODE_UNITS = 50_000;\nconst graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\n\nexport function sanitizeChromeDevtoolsDisplay(value: string, maxCharacters = 50_000) {\n\tconst inputWasTruncated = value.length > MAX_SANITIZER_INPUT_CODE_UNITS;\n\tconst boundedInput = inputWasTruncated\n\t\t? truncateAtGraphemeBoundary(value, MAX_SANITIZER_INPUT_CODE_UNITS)\n\t\t: value;\n\tconst normalizedLineEndings = boundedInput.replace(/\\r\\n/g, \"\\n\");\n\t// Neutralize controls without parsing untrusted terminal sequences; keep printable payload visible.\n\tconst sanitized = Array.from(normalizedLineEndings, (character) => {\n\t\tconst codePoint = character.codePointAt(0) ?? 0;\n\t\tconst unsafeControl =\n\t\t\t(codePoint >= 0 && codePoint <= 8) ||\n\t\t\t(codePoint >= 11 && codePoint <= 31) ||\n\t\t\t(codePoint >= 127 && codePoint <= 159);\n\t\tconst unsafeBidi =\n\t\t\t(codePoint >= 0x202a && codePoint <= 0x202e) || (codePoint >= 0x2066 && codePoint <= 0x2069);\n\t\tconst loneSurrogate = character.length === 1 && codePoint >= 0xd800 && codePoint <= 0xdfff;\n\t\treturn unsafeControl || unsafeBidi || loneSurrogate ? \"\uFFFD\" : character;\n\t}).join(\"\");\n\tconst outputLimit = Math.min(maxCharacters, MAX_SANITIZER_INPUT_CODE_UNITS);\n\tif (!inputWasTruncated && sanitized.length <= outputLimit) return sanitized;\n\n\treturn `${truncateAtGraphemeBoundary(sanitized, Math.max(0, outputLimit - 1))}\u2026`;\n}\n\nfunction truncateAtGraphemeBoundary(value: string, maxCodeUnits: number) {\n\tif (value.length <= maxCodeUnits) return value;\n\tconst boundedLookahead = value.slice(0, Math.max(0, maxCodeUnits) + 2);\n\tlet safeEnd = 0;\n\tfor (const { index, segment } of graphemeSegmenter.segment(boundedLookahead)) {\n\t\tconst segmentEnd = index + segment.length;\n\t\tif (segmentEnd > maxCodeUnits) break;\n\t\tsafeEnd = segmentEnd;\n\t}\n\treturn value.slice(0, safeEnd);\n}\n", "import type { ExtensionAPI, ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport {\n\tbrowserCandidateHint,\n\tbrowserLifecycleState,\n\tbrowserSettingsForOwner,\n\tdevToolsEndpoint,\n\tendpointConfigHint,\n\tendpointSourceLabel,\n\tlaunchAttemptLines,\n\tlaunchHint,\n\tlaunchModeLabel,\n\tmanagedBrowserForOwner,\n} from \"./browser-manager.js\";\nimport { sanitizeChromeDevtoolsDisplay } from \"./display.js\";\nimport {\n\tapplyAvailableChromeDevtoolsTools,\n\tavailableChromeDevtoolsTools,\n\tCHROME_DEVTOOLS_LOAD_TOOL_NAME,\n\tchromeDevtoolsToolExposureMode,\n} from \"./lazy-tools.js\";\nimport { invalidateWebMcpOperations, state, webMcpEnabled } from \"./runtime.js\";\nimport { loadSettings, saveSettings, settingsFilePath } from \"./settings.js\";\nimport {\n\tCHROME_DEVTOOLS_TOOL_NAMES,\n\ttype ChromeDevToolsToolName,\n\tCORE_CHROME_DEVTOOLS_TOOL_NAMES,\n\tisWebMcpToolName,\n} from \"./tool-names.js\";\n\nexport { sanitizeChromeDevtoolsDisplay };\n\ntype CommandContext = ExtensionCommandContext;\n\nfunction unique<T>(values: T[]) {\n\treturn Array.from(new Set(values));\n}\n\nfunction formatError(error: unknown) {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\ninterface ToolStatusSummary {\n\tavailabilityStatus: \"enabled\" | \"disabled\" | \"partial\";\n\tavailableChromeToolCount: number;\n\tloadedChromeToolCount: number;\n\tactiveNonChromeToolCount: number;\n\tcapabilityCount: number;\n}\n\ntype ToolSelectionSaveResult = \"saved\" | \"active-tools-changed\" | \"failed\";\n\nexport async function updateChromeDevtoolsTools(\n\tpi: ExtensionAPI,\n\tctx: CommandContext,\n\tselectedTools: readonly ChromeDevToolsToolName[],\n\taction: string,\n) {\n\tconst generation = state.sessionGeneration;\n\tconst result = await transactSelectedTools(pi, ctx, selectedTools, generation);\n\tif (result !== \"saved\" || generation !== state.sessionGeneration) return;\n\tconst status = await buildToolStatusMessage(pi, ctx.sessionManager);\n\tif (generation !== state.sessionGeneration) return;\n\tctx.ui.notify(`Chrome DevTools tool catalog ${action}.\\n\\n${status}`, \"info\");\n}\n\nexport async function setSelectedChromeDevtoolsTools(\n\tpi: ExtensionAPI,\n\tctx: CommandContext,\n\tselectedTools: readonly ChromeDevToolsToolName[],\n\texpectedActiveTools: readonly ChromeDevToolsToolName[],\n): Promise<ToolSelectionSaveResult> {\n\treturn transactSelectedTools(\n\t\tpi,\n\t\tctx,\n\t\tselectedTools,\n\t\tstate.sessionGeneration,\n\t\texpectedActiveTools,\n\t);\n}\n\nlet toolTransactionQueue = Promise.resolve();\n\nexport async function waitForChromeDevtoolsSettings(): Promise<void> {\n\tawait toolTransactionQueue;\n}\n\nfunction transactSelectedTools(\n\tpi: ExtensionAPI,\n\tctx: CommandContext,\n\tselectedTools: readonly ChromeDevToolsToolName[],\n\texpectedGeneration: number,\n\texpectedActiveTools?: readonly ChromeDevToolsToolName[],\n): Promise<ToolSelectionSaveResult> {\n\tconst operation = toolTransactionQueue.then(() =>\n\t\ttransactSelectedToolsNow(pi, ctx, selectedTools, expectedGeneration, expectedActiveTools),\n\t);\n\ttoolTransactionQueue = operation.then(\n\t\t() => undefined,\n\t\t() => undefined,\n\t);\n\treturn operation;\n}\n\nasync function transactSelectedToolsNow(\n\tpi: ExtensionAPI,\n\tctx: CommandContext,\n\tselectedTools: readonly ChromeDevToolsToolName[],\n\texpectedGeneration: number,\n\texpectedActiveTools?: readonly ChromeDevToolsToolName[],\n): Promise<ToolSelectionSaveResult> {\n\tif (expectedGeneration !== state.sessionGeneration) return \"failed\";\n\tif (expectedActiveTools && !arraysEqual(availableChromeDevtoolsTools(pi), expectedActiveTools)) {\n\t\tctx.ui.notify(\n\t\t\t\"Browser tool selection changed while review was open. Review the current state, then apply again.\",\n\t\t\t\"warning\",\n\t\t);\n\t\treturn \"active-tools-changed\";\n\t}\n\tconst previousActiveTools = pi.getActiveTools();\n\tconst previousAvailableTools = availableChromeDevtoolsTools(pi);\n\ttry {\n\t\tconst previousWebMcpTools = previousAvailableTools.filter(isWebMcpToolName);\n\t\tconst selectedWebMcpTools = selectedTools.filter(isWebMcpToolName);\n\t\tif (!arraysEqual(previousWebMcpTools, selectedWebMcpTools)) {\n\t\t\tinvalidateWebMcpOperations(\n\t\t\t\tctx.sessionManager,\n\t\t\t\t\"Chrome DevTools WebMCP gateway availability changed\",\n\t\t\t);\n\t\t}\n\t\tapplyChromeDevtoolsTools(pi, selectedTools);\n\t\tawait persistSettings(selectedTools);\n\t\treturn expectedGeneration === state.sessionGeneration ? \"saved\" : \"failed\";\n\t} catch (error) {\n\t\tlet rollbackError: unknown;\n\t\ttry {\n\t\t\tapplyAvailableChromeDevtoolsTools(pi, previousAvailableTools);\n\t\t\tconst currentNonChromeTools = pi\n\t\t\t\t.getActiveTools()\n\t\t\t\t.filter((name) => !CHROME_DEVTOOLS_TOOL_NAMES.includes(name as ChromeDevToolsToolName));\n\t\t\tconst previousLoadedChromeTools = previousActiveTools.filter((name) =>\n\t\t\t\tCHROME_DEVTOOLS_TOOL_NAMES.includes(name as ChromeDevToolsToolName),\n\t\t\t);\n\t\t\tconst restoredChromeTools =\n\t\t\t\tchromeDevtoolsToolExposureMode(pi) === \"eager\"\n\t\t\t\t\t? previousAvailableTools\n\t\t\t\t\t: previousLoadedChromeTools;\n\t\t\tpi.setActiveTools(unique([...currentNonChromeTools, ...restoredChromeTools]));\n\t\t} catch (caught) {\n\t\t\trollbackError = caught;\n\t\t}\n\t\tif (expectedGeneration !== state.sessionGeneration) return \"failed\";\n\t\tctx.ui.notify(\n\t\t\tsanitizeChromeDevtoolsDisplay(\n\t\t\t\trollbackError\n\t\t\t\t\t? `Chrome DevTools settings save failed: ${formatError(error)}; active-tool rollback failed: ${formatError(rollbackError)}`\n\t\t\t\t\t: `Chrome DevTools settings save failed; active tools restored: ${formatError(error)}`,\n\t\t\t),\n\t\t\t\"warning\",\n\t\t);\n\t\treturn \"failed\";\n\t}\n}\n\nfunction arraysEqual<T>(left: readonly T[], right: readonly T[]) {\n\treturn left.length === right.length && left.every((value, index) => value === right[index]);\n}\n\nexport function applyChromeDevtoolsTools(\n\tpi: ExtensionAPI,\n\tselectedTools: readonly ChromeDevToolsToolName[],\n) {\n\tapplyAvailableChromeDevtoolsTools(pi, selectedTools);\n}\n\nfunction getToolStatusSummary(pi: ExtensionAPI, owner: object): ToolStatusSummary {\n\tconst chromeToolNames = new Set<string>(CHROME_DEVTOOLS_TOOL_NAMES);\n\tconst activeToolNames = new Set(pi.getActiveTools());\n\tconst loadedChromeToolCount = CHROME_DEVTOOLS_TOOL_NAMES.filter((name) =>\n\t\tactiveToolNames.has(name),\n\t).length;\n\tconst availableChromeToolCount = availableChromeDevtoolsTools(pi).length;\n\tconst activeNonChromeToolCount = Array.from(activeToolNames).filter(\n\t\t(name) => !chromeToolNames.has(name) && name !== CHROME_DEVTOOLS_LOAD_TOOL_NAME,\n\t).length;\n\tconst capabilityCount = effectiveCatalog(owner).length;\n\tconst availabilityStatus =\n\t\tavailableChromeToolCount === capabilityCount\n\t\t\t? \"enabled\"\n\t\t\t: availableChromeToolCount === 0\n\t\t\t\t? \"disabled\"\n\t\t\t\t: \"partial\";\n\n\treturn {\n\t\tavailabilityStatus,\n\t\tavailableChromeToolCount,\n\t\tloadedChromeToolCount,\n\t\tactiveNonChromeToolCount,\n\t\tcapabilityCount,\n\t};\n}\n\nexport async function buildToolStatusMessage(pi: ExtensionAPI, owner: object) {\n\tconst summary = getToolStatusSummary(pi, owner);\n\tconst persistedSetting = await persistedSettingLabel();\n\treturn sanitizeChromeDevtoolsDisplay(\n\t\t[\n\t\t\t`Chrome DevTools tools available: ${formatRuntimeStatus(summary)}`,\n\t\t\t`Tool exposure: ${chromeDevtoolsToolExposureMode(pi)}`,\n\t\t\t`Loaded capability tools this session: ${summary.loadedChromeToolCount}/${summary.capabilityCount}`,\n\t\t\t`WebMCP: ${webMcpEnabled(owner) ? \"enabled \u00B7 experimental \u00B7 confirmation required for every call\" : \"disabled \u00B7 experimental\"}`,\n\t\t\t`Loader: ${pi.getActiveTools().includes(CHROME_DEVTOOLS_LOAD_TOOL_NAME) ? \"active\" : \"inactive\"}`,\n\t\t\t`Persisted tool catalog: ${persistedSetting}`,\n\t\t\t...browserSettingsStatusLines(owner),\n\t\t\t...(state.settingsNotice ? [`Settings note: ${state.settingsNotice}`] : []),\n\t\t\t`Other active tools preserved: ${summary.activeNonChromeToolCount}`,\n\t\t\t`Endpoint: ${devToolsEndpoint(owner)}`,\n\t\t\t`Endpoint source: ${endpointSourceLabel(owner)}`,\n\t\t\t`Launch mode: ${launchModeLabel(owner)}`,\n\t\t\t...launchAttemptLines(owner),\n\t\t].join(\"\\n\"),\n\t);\n}\n\nexport function buildQuickstartMessage(owner: object) {\n\treturn buildSettingsSetupMessage(owner);\n}\n\nexport function buildBrowserStatusMessage(owner?: object) {\n\tconst browser = browserSettingsForOwner(owner);\n\tconst lifecycle = browserLifecycleState(owner);\n\tconst webMcpIsEnabled = owner ? webMcpEnabled(owner) : false;\n\tconst browserState =\n\t\tlifecycle === \"starting\"\n\t\t\t? \"starting managed browser\"\n\t\t\t: lifecycle === \"running\"\n\t\t\t\t? \"managed browser running\"\n\t\t\t\t: lifecycle === \"exited\"\n\t\t\t\t\t? \"managed browser exited\"\n\t\t\t\t\t: lifecycle === \"failed\"\n\t\t\t\t\t\t? \"last launch failed\"\n\t\t\t\t\t\t: \"not started; connection has not been checked\";\n\tconst needsRecovery = lifecycle === \"exited\" || lifecycle === \"failed\";\n\treturn sanitizeChromeDevtoolsDisplay(\n\t\t[\n\t\t\t`Browser: ${browserState}`,\n\t\t\t\"Viewing this status does not probe the endpoint or launch Chrome.\",\n\t\t\t`Endpoint: ${devToolsEndpoint(owner)}`,\n\t\t\t`Endpoint source: ${endpointSourceLabel(owner)}`,\n\t\t\t`Launch mode: ${launchModeLabel(owner)}`,\n\t\t\t`Unpacked extensions: ${browser.extensionPaths.length} (${browser.extensionPathsSource})`,\n\t\t\t`WebMCP: ${webMcpIsEnabled ? \"enabled \u00B7 experimental\" : \"disabled \u00B7 experimental\"}`,\n\t\t\t...(webMcpIsEnabled && !managedBrowserForOwner(owner)?.ready\n\t\t\t\t? [\n\t\t\t\t\t\t\"WebMCP warning: attached browser profiles may contain everyday authenticated sessions and sensitive state.\",\n\t\t\t\t\t]\n\t\t\t\t: []),\n\t\t\t...(browser.extensionPaths.length > 0\n\t\t\t\t? [\"Unpacked extensions execute trusted browser code in an isolated managed browser.\"]\n\t\t\t\t: []),\n\t\t\t...launchAttemptLines(owner),\n\t\t\t...(needsRecovery ? [launchHint(owner), endpointConfigHint()] : []),\n\t\t].join(\"\\n\"),\n\t);\n}\n\nexport function buildSettingsSetupMessage(owner: object) {\n\treturn sanitizeChromeDevtoolsDisplay(\n\t\t[\n\t\t\t`Chrome DevTools endpoint: ${devToolsEndpoint(owner)}`,\n\t\t\t`Endpoint source: ${endpointSourceLabel(owner)}`,\n\t\t\t`Launch mode: ${launchModeLabel(owner)}`,\n\t\t\t...browserSettingsStatusLines(owner),\n\t\t\tlaunchHint(owner),\n\t\t\tbrowserCandidateHint(owner),\n\t\t\t...launchAttemptLines(owner),\n\t\t\tendpointConfigHint(),\n\t\t].join(\"\\n\"),\n\t);\n}\n\nfunction browserSettingsStatusLines(owner: object) {\n\tconst browser = browserSettingsForOwner(owner);\n\tconst extensionPaths = browser.extensionPaths;\n\tconst extensionLines =\n\t\textensionPaths.length > 0\n\t\t\t? extensionPaths.map((extensionPath) => ` - ${extensionPath}`)\n\t\t\t: [\" - none\"];\n\treturn [\n\t\t`Settings file: ${state.settingsFilePath ?? settingsFilePath()} (user)`,\n\t\t...(state.projectSettingsFilePath\n\t\t\t? [\n\t\t\t\t\t`Project settings: ${state.projectSettingsFilePath} (${state.projectSettingsTrusted ? \"trusted\" : \"untrusted; ignored\"})`,\n\t\t\t\t]\n\t\t\t: []),\n\t\t`Auto-launch: ${browser.autoLaunchEnabled ? \"on\" : \"off\"} (${browser.autoLaunchSource})`,\n\t\t`Browser executable: ${browser.executablePath ?? \"automatic discovery\"} (${browser.executablePathSource})`,\n\t\t`Unpacked extensions (${browser.extensionPathsSource}):`,\n\t\t...extensionLines,\n\t\t`WebMCP: ${webMcpEnabled(owner) ? \"enabled \u00B7 experimental \u00B7 every call requires confirmation\" : \"disabled \u00B7 experimental\"}`,\n\t\t\"Confirmed menu settings apply before the next browser connection; manual JSON edits require /reload or session replacement.\",\n\t\t...(extensionPaths.length > 0\n\t\t\t? [\n\t\t\t\t\t\"Unpacked extensions require Chrome for Testing or Chromium and execute trusted browser code.\",\n\t\t\t\t]\n\t\t\t: []),\n\t];\n}\n\nexport function buildCommandGuide(owner: object) {\n\treturn [\n\t\t\"Chrome DevTools commands:\",\n\t\t`WebMCP: ${webMcpEnabled(owner) ? \"enabled\" : \"disabled\"} \u00B7 experimental \u00B7 every page-provided call requires confirmation`,\n\t\t\"/chrome-devtools \u2014 open this menu\",\n\t\t\"/chrome-devtools help \u2014 show command usage\",\n\t\t\"/chrome-devtools quickstart \u2014 show endpoint and launch help\",\n\t\t\"/chrome-devtools status \u2014 show tool and settings status\",\n\t\t\"/chrome-devtools settings \u2014 edit browser connection settings\",\n\t\t\"/chrome-devtools tools \u2014 choose available Chrome DevTools tools\",\n\t\t\"/chrome-devtools toggle|select \u2014 compatibility aliases for tools\",\n\t\t\"/chrome-devtools enable|on \u2014 make all Chrome DevTools tools available\",\n\t\t\"/chrome-devtools disable|off \u2014 make all Chrome DevTools capability tools unavailable\",\n\t].join(\"\\n\");\n}\n\nexport function allChromeDevtoolsTools(owner: object) {\n\treturn effectiveCatalog(owner);\n}\n\nexport function orderedChromeDevtoolsTools(selectedTools: ReadonlySet<ChromeDevToolsToolName>) {\n\treturn CHROME_DEVTOOLS_TOOL_NAMES.filter((toolName) => selectedTools.has(toolName));\n}\n\nfunction formatRuntimeStatus(summary: ToolStatusSummary) {\n\treturn `${summary.availabilityStatus} (${summary.availableChromeToolCount}/${summary.capabilityCount} available)`;\n}\n\nasync function persistedSettingLabel() {\n\tconst settings = await loadSettings();\n\tif (settings.kind === \"loaded\" && settings.settings.tools) {\n\t\treturn formatPersistedSelection(settings.settings.tools);\n\t}\n\tif (settings.kind === \"invalid\") {\n\t\treturn `none; current active-tool policy preserved (invalid settings ignored: ${settings.reason})`;\n\t}\n\treturn \"none; current active-tool policy preserved\";\n}\n\nfunction formatPersistedSelection(tools: readonly ChromeDevToolsToolName[]) {\n\tif (tools.length === CHROME_DEVTOOLS_TOOL_NAMES.length) {\n\t\treturn `all available (${tools.length}/${CHROME_DEVTOOLS_TOOL_NAMES.length} selected)`;\n\t}\n\tif (tools.length === 0)\n\t\treturn `all unavailable (0/${CHROME_DEVTOOLS_TOOL_NAMES.length} selected)`;\n\treturn `${tools.length}/${CHROME_DEVTOOLS_TOOL_NAMES.length} selected: ${tools.join(\", \")}`;\n}\n\nfunction effectiveCatalog(owner: object): ChromeDevToolsToolName[] {\n\treturn webMcpEnabled(owner)\n\t\t? [...CHROME_DEVTOOLS_TOOL_NAMES]\n\t\t: [...CORE_CHROME_DEVTOOLS_TOOL_NAMES];\n}\n\nasync function persistSettings(selectedTools: readonly ChromeDevToolsToolName[]) {\n\tawait saveSettings({ tools: [...selectedTools], updatedAt: Date.now() });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["unique"]
|
|
7
|
+
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
buildCommandGuide,
|
|
7
7
|
sanitizeChromeDevtoolsDisplay,
|
|
8
8
|
setSelectedChromeDevtoolsTools
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-LLXOCRNF.js";
|
|
10
10
|
import {
|
|
11
11
|
CHROME_DEVTOOLS_TOOL_NAMES,
|
|
12
12
|
CORE_CHROME_DEVTOOLS_TOOL_NAMES,
|
|
@@ -137,7 +137,7 @@ async function showChromeDevtoolsMenu(pi, ctx, generation) {
|
|
|
137
137
|
return result?.closeParent ? { kind: "close" } : { kind: "stay" };
|
|
138
138
|
},
|
|
139
139
|
settings: async ({ state: current }) => {
|
|
140
|
-
const { showChromeDevtoolsBrowserSettings } = await import("./browser-settings-menu-
|
|
140
|
+
const { showChromeDevtoolsBrowserSettings } = await import("./browser-settings-menu-IMB6HXSU.js");
|
|
141
141
|
if (!isCurrent()) return { kind: "stay" };
|
|
142
142
|
const result = await showChromeDevtoolsBrowserSettings(pi, ctx, generation);
|
|
143
143
|
if (!isCurrent()) return { kind: "stay" };
|
|
@@ -428,4 +428,4 @@ export {
|
|
|
428
428
|
showChromeDevtoolsMenu,
|
|
429
429
|
showChromeDevtoolsToolWorkflow
|
|
430
430
|
};
|
|
431
|
-
//# sourceMappingURL=menu-
|
|
431
|
+
//# sourceMappingURL=menu-UJETYMSB.js.map
|