@narumitw/pi-chrome-devtools 0.51.0 → 0.52.1
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 +74 -42
- package/dist/chunks/browser-settings-menu-L4CZINWO.ts +266 -0
- package/dist/chunks/browser-settings-menu-L4CZINWO.ts.map +7 -0
- package/dist/chunks/chunk-RM7OGXVL.ts +1607 -0
- package/dist/chunks/chunk-RM7OGXVL.ts.map +7 -0
- package/dist/chunks/menu-U4AIAN7V.ts +397 -0
- package/dist/chunks/menu-U4AIAN7V.ts.map +7 -0
- package/dist/index.ts +762 -0
- package/dist/index.ts.map +7 -0
- package/package.json +11 -7
- package/src/browser-manager.ts +3 -5
- package/src/browser-settings-menu.ts +311 -0
- package/src/chrome-devtools.ts +22 -2
- package/src/menu.ts +12 -14
- package/src/runtime.ts +28 -23
- package/src/settings.ts +204 -38
- package/src/tool-selector.ts +3 -1
package/README.md
CHANGED
|
@@ -27,7 +27,8 @@ This package is inspired by [`chrome-devtools-mcp`](https://github.com/ChromeDev
|
|
|
27
27
|
- Retries briefly while Chrome is starting and reports actionable endpoint errors.
|
|
28
28
|
- Shows statusline activity only while Chrome DevTools tools are running.
|
|
29
29
|
- Keeps one loader tool active and exposes matching browser capabilities only when the agent needs them.
|
|
30
|
-
- Provides a state-first `/chrome-devtools` menu for tool availability, browser
|
|
30
|
+
- Provides a state-first `/chrome-devtools` menu for tool availability, editable browser settings,
|
|
31
|
+
browser status, setup, and help.
|
|
31
32
|
- Stages menu-based availability changes for exact review before one confirmed apply.
|
|
32
33
|
- Uses `@narumitw/pi-tui-kit` for width-safe TUI menus and equivalent RPC dialogs.
|
|
33
34
|
- Persists the Chrome DevTools lazy-load catalog across Pi restarts.
|
|
@@ -50,17 +51,39 @@ Try this package locally from the repository root:
|
|
|
50
51
|
pi -e ./packages/pi-chrome-devtools
|
|
51
52
|
```
|
|
52
53
|
|
|
54
|
+
The package declares `dist/index.ts`, so an unbuilt local checkout must run `npm --workspace @narumitw/pi-chrome-devtools run build` before Pi loads the package directory.
|
|
55
|
+
|
|
56
|
+
`just try chrome-devtools` runs that build automatically.
|
|
57
|
+
|
|
53
58
|
## 🚀 Browser startup
|
|
54
59
|
|
|
55
|
-
Without unpacked extensions, the extension first tries
|
|
56
|
-
`127.0.0.1:9222`. If that local endpoint is unavailable
|
|
57
|
-
Chromium-family browser with an isolated temp profile and retries
|
|
58
|
-
are reused and are never terminated by the extension.
|
|
60
|
+
Without unpacked extensions, the extension first tries `browser.endpoint`, defaulting to
|
|
61
|
+
`http://127.0.0.1:9222`. If that local endpoint is unavailable and `browser.autoLaunch` is `true`, it
|
|
62
|
+
lazily launches an extension-owned Chromium-family browser with an isolated temp profile and retries
|
|
63
|
+
the CDP request. Existing endpoints are reused and are never terminated by the extension.
|
|
64
|
+
|
|
65
|
+
Configure the canonical user file at
|
|
66
|
+
`${PI_CODING_AGENT_DIR:-~/.pi/agent}/pi-chrome-devtools.json`:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"browser": {
|
|
71
|
+
"endpoint": "http://127.0.0.1:9222",
|
|
72
|
+
"autoLaunch": true,
|
|
73
|
+
"executablePath": "/absolute/path/to/chromium"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`browser.endpoint` must be an HTTP origin with an explicit port and no credentials, path, query, or
|
|
79
|
+
fragment. Omitting it keeps attach-first behavior on `127.0.0.1:9222` and lets a managed launch use
|
|
80
|
+
Chrome's dynamic DevTools port mode (`--remote-debugging-port=0`). Explicitly saving an endpoint pins
|
|
81
|
+
managed launches to that port. `browser.autoLaunch` defaults to `true`. `browser.executablePath` is
|
|
82
|
+
optional and must be an absolute path; when absent, normal browser discovery applies.
|
|
59
83
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
`
|
|
63
|
-
fall back to the default attach-first behavior.
|
|
84
|
+
The configured endpoint must expose the standard CDP HTTP discovery routes such as `/json/version`
|
|
85
|
+
and `/json/list`. Chrome's newer built-in permission flow can listen on port `9222` while returning
|
|
86
|
+
`404` from those routes; setting the same HTTP origin does not by itself make that flow compatible.
|
|
64
87
|
|
|
65
88
|
### Unpacked extensions
|
|
66
89
|
|
|
@@ -68,8 +91,7 @@ fall back to the default attach-first behavior.
|
|
|
68
91
|
> An unpacked extension executes privileged browser code. Load only code you trust. Project settings
|
|
69
92
|
> are honored only when Pi reports the project as trusted.
|
|
70
93
|
|
|
71
|
-
|
|
72
|
-
`${PI_CODING_AGENT_DIR:-~/.pi/agent}/pi-chrome-devtools.json`:
|
|
94
|
+
Add trusted unpacked-extension paths to the same canonical user file:
|
|
73
95
|
|
|
74
96
|
```json
|
|
75
97
|
{
|
|
@@ -101,9 +123,10 @@ A trusted project can replace the user extension list in
|
|
|
101
123
|
```
|
|
102
124
|
|
|
103
125
|
Project `extensionPaths` replace, rather than append to, the user array. A project file cannot
|
|
104
|
-
override `browser.
|
|
105
|
-
Effective precedence is defaults, user settings,
|
|
106
|
-
|
|
126
|
+
override `browser.endpoint`, `browser.autoLaunch`, or `browser.executablePath`; browser connection
|
|
127
|
+
settings remain machine-owned user configuration. Effective precedence is defaults, user settings,
|
|
128
|
+
trusted project extension paths, then deprecated environment overrides. No new environment variable
|
|
129
|
+
is required.
|
|
107
130
|
|
|
108
131
|
When `extensionPaths` is non-empty, the extension skips attach-first behavior and starts an isolated,
|
|
109
132
|
extension-owned managed browser with `--disable-extensions-except` and `--load-extension`. It fails
|
|
@@ -116,24 +139,17 @@ old managed browser is closed before the new configuration is applied. Missing f
|
|
|
116
139
|
existing no-extension behavior. Invalid JSON, invalid browser values, and missing manifests are left
|
|
117
140
|
unchanged and ignored with an actionable warning.
|
|
118
141
|
|
|
119
|
-
###
|
|
120
|
-
|
|
121
|
-
`PI_CHROME_DEVTOOLS_BROWSER` remains the explicit runtime executable override. Without unpacked
|
|
122
|
-
extensions, browser discovery still checks platform-specific Chrome, Chromium, Brave, and Microsoft
|
|
123
|
-
Edge candidates. Disable auto-launch to keep the manual flow:
|
|
124
|
-
|
|
125
|
-
```bash
|
|
126
|
-
PI_CHROME_DEVTOOLS_AUTO_LAUNCH=0 pi -e ./packages/pi-chrome-devtools
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
Force an executable or endpoint if needed:
|
|
142
|
+
### Deprecated environment overrides and manual endpoints
|
|
130
143
|
|
|
131
|
-
|
|
132
|
-
PI_CHROME_DEVTOOLS_BROWSER
|
|
133
|
-
|
|
134
|
-
|
|
144
|
+
The existing `PI_CHROME_DEVTOOLS_HOST`, `PI_CHROME_DEVTOOLS_PORT`,
|
|
145
|
+
`PI_CHROME_DEVTOOLS_AUTO_LAUNCH`, and `PI_CHROME_DEVTOOLS_BROWSER` variables remain temporary
|
|
146
|
+
compatibility overrides. They still take precedence over JSON, but every session that sees one emits
|
|
147
|
+
a deprecation warning. Move their values to `browser.endpoint`, `browser.autoLaunch`, and
|
|
148
|
+
`browser.executablePath`; the variables will be removed in a future version.
|
|
135
149
|
|
|
136
|
-
|
|
150
|
+
Without unpacked extensions, browser discovery still checks platform-specific Chrome, Chromium,
|
|
151
|
+
Brave, and Microsoft Edge candidates. Manual launch remains available when no unpacked extensions are
|
|
152
|
+
configured:
|
|
137
153
|
|
|
138
154
|
```bash
|
|
139
155
|
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/pi-chrome-devtools
|
|
@@ -212,7 +228,9 @@ an action. The five actions stay on one level:
|
|
|
212
228
|
context-appropriate bulk change before applying it.
|
|
213
229
|
- **Browser status** — inspect runtime, endpoint, launch mode, and the last launch attempt without
|
|
214
230
|
probing the endpoint or starting Chrome.
|
|
215
|
-
- **
|
|
231
|
+
- **Browser settings** — immediately save the endpoint, auto-launch policy, or browser executable;
|
|
232
|
+
inspect unpacked-extension paths and effective sources. A deprecated environment override remains
|
|
233
|
+
effective until removed even when its underlying JSON value changes.
|
|
216
234
|
- **Help** — view command usage and return to the menu.
|
|
217
235
|
|
|
218
236
|
In the tool screen, **Select all** and **Select none** are unambiguous shortcuts; individual rows use
|
|
@@ -229,6 +247,7 @@ Direct subcommands are also available:
|
|
|
229
247
|
/chrome-devtools help
|
|
230
248
|
/chrome-devtools quickstart
|
|
231
249
|
/chrome-devtools status
|
|
250
|
+
/chrome-devtools settings
|
|
232
251
|
/chrome-devtools tools
|
|
233
252
|
/chrome-devtools toggle
|
|
234
253
|
/chrome-devtools enable
|
|
@@ -244,6 +263,7 @@ Compatibility aliases remain available: `toggle` and `select` mean `tools`, `on`
|
|
|
244
263
|
- `status` shows available and loaded capability counts, loader state, the persisted catalog,
|
|
245
264
|
settings file path, endpoint source, launch mode, last launch attempt, and active non-Chrome tool
|
|
246
265
|
count.
|
|
266
|
+
- `settings` opens the same immediate-save browser settings flow used by the menu.
|
|
247
267
|
- `tools` opens the same staged, width-safe availability and review flow used by the menu.
|
|
248
268
|
- `toggle` and `select` are compatibility aliases for `tools`.
|
|
249
269
|
- `enable` makes all five capability tools available to the loader and saves that catalog; `on` is a
|
|
@@ -251,11 +271,13 @@ Compatibility aliases remain available: `toggle` and `select` mean `tools`, `on`
|
|
|
251
271
|
- `disable` makes all five capability tools unavailable and saves the empty catalog; `off` is a
|
|
252
272
|
compatibility alias. The slash command and `chrome_devtools_load` remain available.
|
|
253
273
|
|
|
254
|
-
The menu, `tools`, `help`, `quickstart`, and `status` require TUI or RPC mode so their
|
|
255
|
-
observable. TUI uses keyboard navigation and injected Pi keybindings; RPC receives
|
|
256
|
-
standard dialogs. In print and JSON modes, interactive and informational routes reject
|
|
257
|
-
instead of silently opening unavailable UI. The immediate `enable`/`disable` routes remain
|
|
258
|
-
for deterministic non-interactive use.
|
|
274
|
+
The menu, `settings`, `tools`, `help`, `quickstart`, and `status` require TUI or RPC mode so their
|
|
275
|
+
result is observable. TUI uses keyboard navigation and injected Pi keybindings; RPC receives
|
|
276
|
+
equivalent standard dialogs. In print and JSON modes, interactive and informational routes reject
|
|
277
|
+
explicitly instead of silently opening unavailable UI. The immediate `enable`/`disable` routes remain
|
|
278
|
+
available for deterministic non-interactive use.
|
|
279
|
+
|
|
280
|
+
## ⚙️ Settings
|
|
259
281
|
|
|
260
282
|
The available capability names are saved to:
|
|
261
283
|
|
|
@@ -263,14 +285,19 @@ The available capability names are saved to:
|
|
|
263
285
|
${PI_CODING_AGENT_DIR:-~/.pi/agent}/pi-chrome-devtools.json
|
|
264
286
|
```
|
|
265
287
|
|
|
288
|
+
The same file owns `browser.endpoint`, `browser.autoLaunch`, `browser.executablePath`, and
|
|
289
|
+
`browser.extensionPaths`. Browser connection fields are machine-owned user settings; trusted project
|
|
290
|
+
files may replace only `browser.extensionPaths`. Confirmed menu changes apply before the next browser
|
|
291
|
+
connection and close only an extension-owned managed browser. Manual JSON edits and unpacked-extension
|
|
292
|
+
changes apply after `/reload` or session replacement.
|
|
293
|
+
|
|
266
294
|
When the file is missing or invalid, the extension preserves Pi's current Chrome DevTools
|
|
267
295
|
availability policy instead of replacing it. A valid saved catalog is restored on Pi startup and
|
|
268
296
|
`/reload`, while its capability definitions remain deferred. A missing file is created by the first
|
|
269
|
-
confirmed
|
|
270
|
-
|
|
271
|
-
JSON or invalid recognized fields make menu mutation unavailable and block direct
|
|
272
|
-
replacement; a failed save restores the prior
|
|
273
|
-
while preserving other extensions' current tools.
|
|
297
|
+
confirmed browser or tool setting. Within one Pi process, all browser and tool saves run in invocation
|
|
298
|
+
order, reread the latest valid document, publish by temporary-file rename, and preserve unknown
|
|
299
|
+
fields. Malformed JSON or invalid recognized fields make menu mutation unavailable and block direct
|
|
300
|
+
saves without replacement; a failed save restores the prior displayed and effective state.
|
|
274
301
|
|
|
275
302
|
Compatibility: older versions used `pi-chrome-devtools-settings.json`. A legacy-only file remains
|
|
276
303
|
readable with a warning and is never modified automatically; rename it to
|
|
@@ -290,6 +317,9 @@ filename is deprecated and will be removed in a future major release.
|
|
|
290
317
|
|
|
291
318
|
```txt
|
|
292
319
|
packages/pi-chrome-devtools/
|
|
320
|
+
├── dist/ # Generated TypeScript runtime loaded by Jiti
|
|
321
|
+
├── scripts/
|
|
322
|
+
│ └── build-runtime.mjs # Deterministic runtime builder and boundary validator
|
|
293
323
|
├── src/
|
|
294
324
|
│ ├── index.ts # Pi package entrypoint
|
|
295
325
|
│ ├── chrome-devtools.ts # Extension registration and command orchestration
|
|
@@ -306,11 +336,13 @@ packages/pi-chrome-devtools/
|
|
|
306
336
|
```json
|
|
307
337
|
{
|
|
308
338
|
"pi": {
|
|
309
|
-
"extensions": ["./
|
|
339
|
+
"extensions": ["./dist/index.ts"]
|
|
310
340
|
}
|
|
311
341
|
}
|
|
312
342
|
```
|
|
313
343
|
|
|
344
|
+
The generated runtime is built from the authoritative `src/index.ts` graph and does not import back into `src`.
|
|
345
|
+
|
|
314
346
|
## 🔎 Keywords
|
|
315
347
|
|
|
316
348
|
Pi extension, Pi coding agent, Chrome DevTools Protocol, CDP, browser automation, web debugging, JavaScript evaluation, screenshot automation, AI coding agent tools.
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
|
+
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
|
+
import {
|
|
4
|
+
applyRuntimeBrowserSettings,
|
|
5
|
+
loadSettings,
|
|
6
|
+
parseBrowserEndpoint,
|
|
7
|
+
sanitizeChromeDevtoolsDisplay,
|
|
8
|
+
saveBrowserSettings,
|
|
9
|
+
shutdownManagedBrowser,
|
|
10
|
+
state
|
|
11
|
+
} from "./chunk-RM7OGXVL.js";
|
|
12
|
+
|
|
13
|
+
// src/browser-settings-menu.ts
|
|
14
|
+
import { isAbsolute } from "node:path";
|
|
15
|
+
import { defineMenu, runMenu } from "@narumitw/pi-tui-kit";
|
|
16
|
+
async function showChromeDevtoolsBrowserSettings(ctx, generation) {
|
|
17
|
+
const ownerSignal = state.sessionController.signal;
|
|
18
|
+
const isCurrent2 = () => generation === state.sessionGeneration && !ownerSignal.aborted;
|
|
19
|
+
const projectTrusted = ctx.isProjectTrusted();
|
|
20
|
+
const menu = defineMenu({
|
|
21
|
+
start: "settings",
|
|
22
|
+
screens: {
|
|
23
|
+
settings: ({ state: current }) => {
|
|
24
|
+
if (current.load.userFile.kind === "invalid") return invalidSettingsScreen(current.load);
|
|
25
|
+
const browser = current.load.effectiveBrowser;
|
|
26
|
+
return {
|
|
27
|
+
kind: "settings",
|
|
28
|
+
title: "Chrome DevTools Browser settings",
|
|
29
|
+
lines: settingsContextLines(current.load),
|
|
30
|
+
items: [
|
|
31
|
+
{
|
|
32
|
+
id: "endpoint",
|
|
33
|
+
label: "DevTools endpoint",
|
|
34
|
+
description: 'HTTP origin with an explicit port; enter "default" to restore 127.0.0.1:9222.',
|
|
35
|
+
currentValue: sanitizeChromeDevtoolsDisplay(browser.endpoint),
|
|
36
|
+
action: "open-endpoint"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "auto-launch",
|
|
40
|
+
label: "Auto-launch",
|
|
41
|
+
description: "Launch an isolated managed browser when a local endpoint is unavailable.",
|
|
42
|
+
currentValue: browser.autoLaunchEnabled ? "On" : "Off",
|
|
43
|
+
values: ["On", "Off"],
|
|
44
|
+
action: "set-auto-launch"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: "executable",
|
|
48
|
+
label: "Browser executable",
|
|
49
|
+
description: 'Absolute executable path; enter "automatic" to restore browser discovery.',
|
|
50
|
+
currentValue: sanitizeChromeDevtoolsDisplay(browser.executablePath ?? "Automatic"),
|
|
51
|
+
action: "open-executable"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "extensions",
|
|
55
|
+
label: "Unpacked extensions",
|
|
56
|
+
description: "Inspect trusted extension paths configured in user or project JSON.",
|
|
57
|
+
currentValue: `${browser.extensionPaths.length} configured`,
|
|
58
|
+
action: "show-extensions"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
endpoint: ({ state: current }) => ({
|
|
64
|
+
kind: "input",
|
|
65
|
+
title: "DevTools endpoint",
|
|
66
|
+
lines: [
|
|
67
|
+
sanitizeChromeDevtoolsDisplay(
|
|
68
|
+
`Current effective endpoint: ${current.load.effectiveBrowser.endpoint}`
|
|
69
|
+
),
|
|
70
|
+
'Enter an HTTP origin with an explicit port, or "default".'
|
|
71
|
+
],
|
|
72
|
+
placeholder: "http://127.0.0.1:9222",
|
|
73
|
+
action: "save-endpoint",
|
|
74
|
+
hint: "back"
|
|
75
|
+
}),
|
|
76
|
+
executable: ({ state: current }) => ({
|
|
77
|
+
kind: "input",
|
|
78
|
+
title: "Browser executable",
|
|
79
|
+
lines: [
|
|
80
|
+
sanitizeChromeDevtoolsDisplay(
|
|
81
|
+
`Current effective executable: ${current.load.effectiveBrowser.executablePath ?? "automatic discovery"}`
|
|
82
|
+
),
|
|
83
|
+
'Enter an absolute path, or "automatic".'
|
|
84
|
+
],
|
|
85
|
+
placeholder: "absolute browser executable path",
|
|
86
|
+
action: "save-executable",
|
|
87
|
+
hint: "back"
|
|
88
|
+
}),
|
|
89
|
+
extensions: ({ state: current }) => ({
|
|
90
|
+
kind: "detail",
|
|
91
|
+
title: "Unpacked extensions",
|
|
92
|
+
lines: extensionDetailLines(current.load),
|
|
93
|
+
hint: "back"
|
|
94
|
+
})
|
|
95
|
+
},
|
|
96
|
+
actions: {
|
|
97
|
+
"open-endpoint": () => ({ kind: "to", screen: "endpoint" }),
|
|
98
|
+
"save-endpoint": async ({ value, signal }) => {
|
|
99
|
+
if (value === void 0) return { kind: "rejected" };
|
|
100
|
+
let endpoint;
|
|
101
|
+
try {
|
|
102
|
+
const trimmed = value.trim();
|
|
103
|
+
endpoint = trimmed.toLowerCase() === "default" ? null : parseBrowserEndpoint(trimmed).endpoint;
|
|
104
|
+
} catch (error) {
|
|
105
|
+
notifySaveFailure(ctx, error);
|
|
106
|
+
return { kind: "rejected" };
|
|
107
|
+
}
|
|
108
|
+
const saved = await saveAndApplyBrowserPatch(
|
|
109
|
+
ctx,
|
|
110
|
+
generation,
|
|
111
|
+
ownerSignal,
|
|
112
|
+
signal,
|
|
113
|
+
projectTrusted,
|
|
114
|
+
{ endpoint }
|
|
115
|
+
);
|
|
116
|
+
if (!saved) return { kind: "rejected" };
|
|
117
|
+
notifyEffectiveSave(
|
|
118
|
+
ctx,
|
|
119
|
+
"endpoint",
|
|
120
|
+
saved.effectiveBrowser.endpoint,
|
|
121
|
+
saved.effectiveBrowser.endpointSource
|
|
122
|
+
);
|
|
123
|
+
return { kind: "back" };
|
|
124
|
+
},
|
|
125
|
+
"set-auto-launch": async ({ value, signal }) => {
|
|
126
|
+
if (value !== "On" && value !== "Off") return { kind: "rejected" };
|
|
127
|
+
const saved = await saveAndApplyBrowserPatch(
|
|
128
|
+
ctx,
|
|
129
|
+
generation,
|
|
130
|
+
ownerSignal,
|
|
131
|
+
signal,
|
|
132
|
+
projectTrusted,
|
|
133
|
+
{ autoLaunch: value === "On" }
|
|
134
|
+
);
|
|
135
|
+
if (!saved) return { kind: "rejected" };
|
|
136
|
+
notifyEffectiveSave(
|
|
137
|
+
ctx,
|
|
138
|
+
"auto-launch",
|
|
139
|
+
saved.effectiveBrowser.autoLaunchEnabled ? "On" : "Off",
|
|
140
|
+
saved.effectiveBrowser.autoLaunchSource
|
|
141
|
+
);
|
|
142
|
+
return { kind: "stay" };
|
|
143
|
+
},
|
|
144
|
+
"open-executable": () => ({ kind: "to", screen: "executable" }),
|
|
145
|
+
"save-executable": async ({ value, signal }) => {
|
|
146
|
+
if (value === void 0) return { kind: "rejected" };
|
|
147
|
+
const trimmed = value.trim();
|
|
148
|
+
const reset = ["automatic", "default", "none"].includes(trimmed.toLowerCase());
|
|
149
|
+
if (!reset && (!trimmed || !isAbsolute(trimmed))) {
|
|
150
|
+
notifySaveFailure(ctx, new Error('Enter an absolute path or "automatic".'));
|
|
151
|
+
return { kind: "rejected" };
|
|
152
|
+
}
|
|
153
|
+
const executablePath = reset ? null : trimmed;
|
|
154
|
+
const saved = await saveAndApplyBrowserPatch(
|
|
155
|
+
ctx,
|
|
156
|
+
generation,
|
|
157
|
+
ownerSignal,
|
|
158
|
+
signal,
|
|
159
|
+
projectTrusted,
|
|
160
|
+
{ executablePath }
|
|
161
|
+
);
|
|
162
|
+
if (!saved) return { kind: "rejected" };
|
|
163
|
+
notifyEffectiveSave(
|
|
164
|
+
ctx,
|
|
165
|
+
"browser executable",
|
|
166
|
+
saved.effectiveBrowser.executablePath ?? "automatic discovery",
|
|
167
|
+
saved.effectiveBrowser.executablePathSource
|
|
168
|
+
);
|
|
169
|
+
return { kind: "back" };
|
|
170
|
+
},
|
|
171
|
+
"show-extensions": () => ({ kind: "to", screen: "extensions" })
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
const result = await runMenu(ctx, menu, {
|
|
175
|
+
getState: async ({ signal }) => {
|
|
176
|
+
signal.throwIfAborted();
|
|
177
|
+
const load = await loadSettings({ cwd: ctx.cwd, projectTrusted });
|
|
178
|
+
signal.throwIfAborted();
|
|
179
|
+
return { load };
|
|
180
|
+
},
|
|
181
|
+
signal: ownerSignal,
|
|
182
|
+
isCurrent: isCurrent2,
|
|
183
|
+
onError: (currentCtx, error) => currentCtx.ui.notify(
|
|
184
|
+
sanitizeChromeDevtoolsDisplay(
|
|
185
|
+
`Chrome DevTools browser settings failed: ${formatError(error)}`
|
|
186
|
+
),
|
|
187
|
+
"error"
|
|
188
|
+
)
|
|
189
|
+
});
|
|
190
|
+
return { closeParent: result.kind === "closed" && result.reason === "close" };
|
|
191
|
+
}
|
|
192
|
+
async function saveAndApplyBrowserPatch(ctx, generation, ownerSignal, actionSignal, projectTrusted, patch) {
|
|
193
|
+
try {
|
|
194
|
+
await ctx.waitForIdle();
|
|
195
|
+
if (!isCurrent(generation, ownerSignal, actionSignal)) return false;
|
|
196
|
+
await saveBrowserSettings(patch);
|
|
197
|
+
if (!isCurrent(generation, ownerSignal, actionSignal)) return false;
|
|
198
|
+
await shutdownManagedBrowser();
|
|
199
|
+
if (!isCurrent(generation, ownerSignal, actionSignal)) return false;
|
|
200
|
+
const loaded = await loadSettings({ cwd: ctx.cwd, projectTrusted });
|
|
201
|
+
if (!isCurrent(generation, ownerSignal, actionSignal)) return false;
|
|
202
|
+
applyRuntimeBrowserSettings(loaded.effectiveBrowser, loaded.paths, projectTrusted);
|
|
203
|
+
state.settingsNotice = loaded.notice;
|
|
204
|
+
return loaded;
|
|
205
|
+
} catch (error) {
|
|
206
|
+
if (isCurrent(generation, ownerSignal, actionSignal)) notifySaveFailure(ctx, error);
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function isCurrent(generation, ownerSignal, actionSignal) {
|
|
211
|
+
return generation === state.sessionGeneration && !ownerSignal.aborted && !actionSignal.aborted;
|
|
212
|
+
}
|
|
213
|
+
function invalidSettingsScreen(load) {
|
|
214
|
+
const reason = load.userFile.kind === "invalid" ? load.userFile.reason : "The user settings file is unavailable.";
|
|
215
|
+
return {
|
|
216
|
+
kind: "detail",
|
|
217
|
+
title: "Chrome DevTools Browser settings \xB7 Read only",
|
|
218
|
+
lines: [
|
|
219
|
+
sanitizeChromeDevtoolsDisplay(
|
|
220
|
+
`Fix the active user settings before saving; the file will not be overwritten. ${reason}`
|
|
221
|
+
)
|
|
222
|
+
],
|
|
223
|
+
hint: "back"
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function settingsContextLines(load) {
|
|
227
|
+
const browser = load.effectiveBrowser;
|
|
228
|
+
return [
|
|
229
|
+
`User settings \xB7 ${load.paths.user}`,
|
|
230
|
+
`Effective sources: endpoint ${browser.endpointSource} \xB7 auto-launch ${browser.autoLaunchSource} \xB7 executable ${browser.executablePathSource}`,
|
|
231
|
+
...load.notice ? [`Warning: ${load.notice}`] : []
|
|
232
|
+
].map((line) => sanitizeChromeDevtoolsDisplay(line));
|
|
233
|
+
}
|
|
234
|
+
function extensionDetailLines(load) {
|
|
235
|
+
const browser = load.effectiveBrowser;
|
|
236
|
+
return [
|
|
237
|
+
`Effective source: ${browser.extensionPathsSource}`,
|
|
238
|
+
...browser.extensionPaths.length > 0 ? browser.extensionPaths.map((extensionPath) => `- ${extensionPath}`) : ["No unpacked extensions are configured."],
|
|
239
|
+
"Edit browser.extensionPaths in the user JSON or a trusted project JSON, then run /reload.",
|
|
240
|
+
"Unpacked extensions execute privileged browser code; load only paths you trust."
|
|
241
|
+
].map((line) => sanitizeChromeDevtoolsDisplay(line));
|
|
242
|
+
}
|
|
243
|
+
function notifyEffectiveSave(ctx, setting, effectiveValue, source) {
|
|
244
|
+
const overrideNotice = source === "environment" ? " The deprecated environment override remains effective." : "";
|
|
245
|
+
ctx.ui.notify(
|
|
246
|
+
sanitizeChromeDevtoolsDisplay(
|
|
247
|
+
`Chrome DevTools ${setting} saved. Effective ${setting}: ${effectiveValue} (${source}).${overrideNotice}`
|
|
248
|
+
),
|
|
249
|
+
"info"
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
function notifySaveFailure(ctx, error) {
|
|
253
|
+
ctx.ui.notify(
|
|
254
|
+
sanitizeChromeDevtoolsDisplay(
|
|
255
|
+
`Chrome DevTools browser settings save failed; previous settings remain active: ${formatError(error)}`
|
|
256
|
+
),
|
|
257
|
+
"warning"
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
function formatError(error) {
|
|
261
|
+
return error instanceof Error ? error.message : String(error);
|
|
262
|
+
}
|
|
263
|
+
export {
|
|
264
|
+
showChromeDevtoolsBrowserSettings
|
|
265
|
+
};
|
|
266
|
+
//# sourceMappingURL=browser-settings-menu-L4CZINWO.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/browser-settings-menu.ts"],
|
|
4
|
+
"sourcesContent": ["import { isAbsolute } from \"node:path\";\nimport type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { defineMenu, runMenu } from \"@narumitw/pi-tui-kit\";\nimport { shutdownManagedBrowser } from \"./browser-manager.js\";\nimport { applyRuntimeBrowserSettings, state } from \"./runtime.js\";\nimport {\n\ttype BrowserSettingsPatch,\n\ttype BrowserSettingsSource,\n\tloadSettings,\n\tparseBrowserEndpoint,\n\ttype SettingsLoadResult,\n\tsaveBrowserSettings,\n} from \"./settings.js\";\nimport { sanitizeChromeDevtoolsDisplay } from \"./tool-selector.js\";\n\ntype BrowserSettingsScreen = \"settings\" | \"endpoint\" | \"executable\" | \"extensions\";\ntype BrowserSettingsAction =\n\t| \"open-endpoint\"\n\t| \"save-endpoint\"\n\t| \"set-auto-launch\"\n\t| \"open-executable\"\n\t| \"save-executable\"\n\t| \"show-extensions\";\n\ninterface BrowserSettingsMenuState {\n\tload: SettingsLoadResult;\n}\n\ntype CommandContext = ExtensionCommandContext;\n\nexport async function showChromeDevtoolsBrowserSettings(\n\tctx: CommandContext,\n\tgeneration: number,\n): Promise<{ closeParent: boolean }> {\n\tconst ownerSignal = state.sessionController.signal;\n\tconst isCurrent = () => generation === state.sessionGeneration && !ownerSignal.aborted;\n\tconst projectTrusted = ctx.isProjectTrusted();\n\tconst menu = defineMenu<BrowserSettingsMenuState, BrowserSettingsScreen, BrowserSettingsAction>({\n\t\tstart: \"settings\",\n\t\tscreens: {\n\t\t\tsettings: ({ state: current }) => {\n\t\t\t\tif (current.load.userFile.kind === \"invalid\") return invalidSettingsScreen(current.load);\n\t\t\t\tconst browser = current.load.effectiveBrowser;\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"settings\",\n\t\t\t\t\ttitle: \"Chrome DevTools Browser settings\",\n\t\t\t\t\tlines: settingsContextLines(current.load),\n\t\t\t\t\titems: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"endpoint\",\n\t\t\t\t\t\t\tlabel: \"DevTools endpoint\",\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t'HTTP origin with an explicit port; enter \"default\" to restore 127.0.0.1:9222.',\n\t\t\t\t\t\t\tcurrentValue: sanitizeChromeDevtoolsDisplay(browser.endpoint),\n\t\t\t\t\t\t\taction: \"open-endpoint\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"auto-launch\",\n\t\t\t\t\t\t\tlabel: \"Auto-launch\",\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\"Launch an isolated managed browser when a local endpoint is unavailable.\",\n\t\t\t\t\t\t\tcurrentValue: browser.autoLaunchEnabled ? \"On\" : \"Off\",\n\t\t\t\t\t\t\tvalues: [\"On\", \"Off\"],\n\t\t\t\t\t\t\taction: \"set-auto-launch\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"executable\",\n\t\t\t\t\t\t\tlabel: \"Browser executable\",\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t'Absolute executable path; enter \"automatic\" to restore browser discovery.',\n\t\t\t\t\t\t\tcurrentValue: sanitizeChromeDevtoolsDisplay(browser.executablePath ?? \"Automatic\"),\n\t\t\t\t\t\t\taction: \"open-executable\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"extensions\",\n\t\t\t\t\t\t\tlabel: \"Unpacked extensions\",\n\t\t\t\t\t\t\tdescription: \"Inspect trusted extension paths configured in user or project JSON.\",\n\t\t\t\t\t\t\tcurrentValue: `${browser.extensionPaths.length} configured`,\n\t\t\t\t\t\t\taction: \"show-extensions\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t},\n\t\t\tendpoint: ({ state: current }) => ({\n\t\t\t\tkind: \"input\",\n\t\t\t\ttitle: \"DevTools endpoint\",\n\t\t\t\tlines: [\n\t\t\t\t\tsanitizeChromeDevtoolsDisplay(\n\t\t\t\t\t\t`Current effective endpoint: ${current.load.effectiveBrowser.endpoint}`,\n\t\t\t\t\t),\n\t\t\t\t\t'Enter an HTTP origin with an explicit port, or \"default\".',\n\t\t\t\t],\n\t\t\t\tplaceholder: \"http://127.0.0.1:9222\",\n\t\t\t\taction: \"save-endpoint\",\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t\texecutable: ({ state: current }) => ({\n\t\t\t\tkind: \"input\",\n\t\t\t\ttitle: \"Browser executable\",\n\t\t\t\tlines: [\n\t\t\t\t\tsanitizeChromeDevtoolsDisplay(\n\t\t\t\t\t\t`Current effective executable: ${current.load.effectiveBrowser.executablePath ?? \"automatic discovery\"}`,\n\t\t\t\t\t),\n\t\t\t\t\t'Enter an absolute path, or \"automatic\".',\n\t\t\t\t],\n\t\t\t\tplaceholder: \"absolute browser executable path\",\n\t\t\t\taction: \"save-executable\",\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t\textensions: ({ state: current }) => ({\n\t\t\t\tkind: \"detail\",\n\t\t\t\ttitle: \"Unpacked extensions\",\n\t\t\t\tlines: extensionDetailLines(current.load),\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t},\n\t\tactions: {\n\t\t\t\"open-endpoint\": () => ({ kind: \"to\", screen: \"endpoint\" }),\n\t\t\t\"save-endpoint\": async ({ value, signal }) => {\n\t\t\t\tif (value === undefined) return { kind: \"rejected\" };\n\t\t\t\tlet endpoint: string | null;\n\t\t\t\ttry {\n\t\t\t\t\tconst trimmed = value.trim();\n\t\t\t\t\tendpoint =\n\t\t\t\t\t\ttrimmed.toLowerCase() === \"default\" ? null : parseBrowserEndpoint(trimmed).endpoint;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tnotifySaveFailure(ctx, error);\n\t\t\t\t\treturn { kind: \"rejected\" };\n\t\t\t\t}\n\t\t\t\tconst saved = await saveAndApplyBrowserPatch(\n\t\t\t\t\tctx,\n\t\t\t\t\tgeneration,\n\t\t\t\t\townerSignal,\n\t\t\t\t\tsignal,\n\t\t\t\t\tprojectTrusted,\n\t\t\t\t\t{ endpoint },\n\t\t\t\t);\n\t\t\t\tif (!saved) return { kind: \"rejected\" };\n\t\t\t\tnotifyEffectiveSave(\n\t\t\t\t\tctx,\n\t\t\t\t\t\"endpoint\",\n\t\t\t\t\tsaved.effectiveBrowser.endpoint,\n\t\t\t\t\tsaved.effectiveBrowser.endpointSource,\n\t\t\t\t);\n\t\t\t\treturn { kind: \"back\" };\n\t\t\t},\n\t\t\t\"set-auto-launch\": async ({ value, signal }) => {\n\t\t\t\tif (value !== \"On\" && value !== \"Off\") return { kind: \"rejected\" };\n\t\t\t\tconst saved = await saveAndApplyBrowserPatch(\n\t\t\t\t\tctx,\n\t\t\t\t\tgeneration,\n\t\t\t\t\townerSignal,\n\t\t\t\t\tsignal,\n\t\t\t\t\tprojectTrusted,\n\t\t\t\t\t{ autoLaunch: value === \"On\" },\n\t\t\t\t);\n\t\t\t\tif (!saved) return { kind: \"rejected\" };\n\t\t\t\tnotifyEffectiveSave(\n\t\t\t\t\tctx,\n\t\t\t\t\t\"auto-launch\",\n\t\t\t\t\tsaved.effectiveBrowser.autoLaunchEnabled ? \"On\" : \"Off\",\n\t\t\t\t\tsaved.effectiveBrowser.autoLaunchSource,\n\t\t\t\t);\n\t\t\t\treturn { kind: \"stay\" };\n\t\t\t},\n\t\t\t\"open-executable\": () => ({ kind: \"to\", screen: \"executable\" }),\n\t\t\t\"save-executable\": async ({ value, signal }) => {\n\t\t\t\tif (value === undefined) return { kind: \"rejected\" };\n\t\t\t\tconst trimmed = value.trim();\n\t\t\t\tconst reset = [\"automatic\", \"default\", \"none\"].includes(trimmed.toLowerCase());\n\t\t\t\tif (!reset && (!trimmed || !isAbsolute(trimmed))) {\n\t\t\t\t\tnotifySaveFailure(ctx, new Error('Enter an absolute path or \"automatic\".'));\n\t\t\t\t\treturn { kind: \"rejected\" };\n\t\t\t\t}\n\t\t\t\tconst executablePath = reset ? null : trimmed;\n\t\t\t\tconst saved = await saveAndApplyBrowserPatch(\n\t\t\t\t\tctx,\n\t\t\t\t\tgeneration,\n\t\t\t\t\townerSignal,\n\t\t\t\t\tsignal,\n\t\t\t\t\tprojectTrusted,\n\t\t\t\t\t{ executablePath },\n\t\t\t\t);\n\t\t\t\tif (!saved) return { kind: \"rejected\" };\n\t\t\t\tnotifyEffectiveSave(\n\t\t\t\t\tctx,\n\t\t\t\t\t\"browser executable\",\n\t\t\t\t\tsaved.effectiveBrowser.executablePath ?? \"automatic discovery\",\n\t\t\t\t\tsaved.effectiveBrowser.executablePathSource,\n\t\t\t\t);\n\t\t\t\treturn { kind: \"back\" };\n\t\t\t},\n\t\t\t\"show-extensions\": () => ({ kind: \"to\", screen: \"extensions\" }),\n\t\t},\n\t});\n\tconst result = await runMenu(ctx, menu, {\n\t\tgetState: async ({ signal }) => {\n\t\t\tsignal.throwIfAborted();\n\t\t\tconst load = await loadSettings({ cwd: ctx.cwd, projectTrusted });\n\t\t\tsignal.throwIfAborted();\n\t\t\treturn { load };\n\t\t},\n\t\tsignal: ownerSignal,\n\t\tisCurrent,\n\t\tonError: (currentCtx, error) =>\n\t\t\tcurrentCtx.ui.notify(\n\t\t\t\tsanitizeChromeDevtoolsDisplay(\n\t\t\t\t\t`Chrome DevTools browser settings failed: ${formatError(error)}`,\n\t\t\t\t),\n\t\t\t\t\"error\",\n\t\t\t),\n\t});\n\treturn { closeParent: result.kind === \"closed\" && result.reason === \"close\" };\n}\n\nasync function saveAndApplyBrowserPatch(\n\tctx: CommandContext,\n\tgeneration: number,\n\townerSignal: AbortSignal,\n\tactionSignal: AbortSignal,\n\tprojectTrusted: boolean,\n\tpatch: BrowserSettingsPatch,\n) {\n\ttry {\n\t\tawait ctx.waitForIdle();\n\t\tif (!isCurrent(generation, ownerSignal, actionSignal)) return false;\n\t\tawait saveBrowserSettings(patch);\n\t\tif (!isCurrent(generation, ownerSignal, actionSignal)) return false;\n\t\tawait shutdownManagedBrowser();\n\t\tif (!isCurrent(generation, ownerSignal, actionSignal)) return false;\n\t\tconst loaded = await loadSettings({ cwd: ctx.cwd, projectTrusted });\n\t\tif (!isCurrent(generation, ownerSignal, actionSignal)) return false;\n\t\tapplyRuntimeBrowserSettings(loaded.effectiveBrowser, loaded.paths, projectTrusted);\n\t\tstate.settingsNotice = loaded.notice;\n\t\treturn loaded;\n\t} catch (error) {\n\t\tif (isCurrent(generation, ownerSignal, actionSignal)) notifySaveFailure(ctx, error);\n\t\treturn false;\n\t}\n}\n\nfunction isCurrent(generation: number, ownerSignal: AbortSignal, actionSignal: AbortSignal) {\n\treturn generation === state.sessionGeneration && !ownerSignal.aborted && !actionSignal.aborted;\n}\n\nfunction invalidSettingsScreen(load: SettingsLoadResult) {\n\tconst reason =\n\t\tload.userFile.kind === \"invalid\"\n\t\t\t? load.userFile.reason\n\t\t\t: \"The user settings file is unavailable.\";\n\treturn {\n\t\tkind: \"detail\" as const,\n\t\ttitle: \"Chrome DevTools Browser settings \u00B7 Read only\",\n\t\tlines: [\n\t\t\tsanitizeChromeDevtoolsDisplay(\n\t\t\t\t`Fix the active user settings before saving; the file will not be overwritten. ${reason}`,\n\t\t\t),\n\t\t],\n\t\thint: \"back\" as const,\n\t};\n}\n\nfunction settingsContextLines(load: SettingsLoadResult) {\n\tconst browser = load.effectiveBrowser;\n\treturn [\n\t\t`User settings \u00B7 ${load.paths.user}`,\n\t\t`Effective sources: endpoint ${browser.endpointSource} \u00B7 auto-launch ${browser.autoLaunchSource} \u00B7 executable ${browser.executablePathSource}`,\n\t\t...(load.notice ? [`Warning: ${load.notice}`] : []),\n\t].map((line) => sanitizeChromeDevtoolsDisplay(line));\n}\n\nfunction extensionDetailLines(load: SettingsLoadResult) {\n\tconst browser = load.effectiveBrowser;\n\treturn [\n\t\t`Effective source: ${browser.extensionPathsSource}`,\n\t\t...(browser.extensionPaths.length > 0\n\t\t\t? browser.extensionPaths.map((extensionPath) => `- ${extensionPath}`)\n\t\t\t: [\"No unpacked extensions are configured.\"]),\n\t\t\"Edit browser.extensionPaths in the user JSON or a trusted project JSON, then run /reload.\",\n\t\t\"Unpacked extensions execute privileged browser code; load only paths you trust.\",\n\t].map((line) => sanitizeChromeDevtoolsDisplay(line));\n}\n\nfunction notifyEffectiveSave(\n\tctx: CommandContext,\n\tsetting: string,\n\teffectiveValue: string,\n\tsource: BrowserSettingsSource,\n) {\n\tconst overrideNotice =\n\t\tsource === \"environment\" ? \" The deprecated environment override remains effective.\" : \"\";\n\tctx.ui.notify(\n\t\tsanitizeChromeDevtoolsDisplay(\n\t\t\t`Chrome DevTools ${setting} saved. Effective ${setting}: ${effectiveValue} (${source}).${overrideNotice}`,\n\t\t),\n\t\t\"info\",\n\t);\n}\n\nfunction notifySaveFailure(ctx: CommandContext, error: unknown) {\n\tctx.ui.notify(\n\t\tsanitizeChromeDevtoolsDisplay(\n\t\t\t`Chrome DevTools browser settings save failed; previous settings remain active: ${formatError(error)}`,\n\t\t),\n\t\t\"warning\",\n\t);\n}\n\nfunction formatError(error: unknown) {\n\treturn error instanceof Error ? error.message : String(error);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["isCurrent"]
|
|
7
|
+
}
|