@narumitw/pi-chrome-devtools 0.53.2 → 0.53.4

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.
Files changed (40) hide show
  1. package/README.md +1 -0
  2. package/dist/chunks/{browser-settings-menu-IMB6HXSU.js → browser-settings-menu-FVMCCUPM.ts} +16 -42
  3. package/dist/chunks/browser-settings-menu-FVMCCUPM.ts.map +7 -0
  4. package/dist/chunks/{chunk-GTTYS5GT.js → chunk-4B3EQHOH.ts} +2 -2
  5. package/dist/chunks/chunk-4B3EQHOH.ts.map +7 -0
  6. package/dist/chunks/{chunk-SRT3UUIP.js → chunk-LSJSDY2M.ts} +23 -74
  7. package/dist/chunks/chunk-LSJSDY2M.ts.map +7 -0
  8. package/dist/chunks/{chunk-LLXOCRNF.js → chunk-V7N3WI5B.ts} +12 -33
  9. package/dist/chunks/chunk-V7N3WI5B.ts.map +7 -0
  10. package/dist/chunks/{menu-UJETYMSB.js → menu-MTPSLDHZ.ts} +10 -23
  11. package/dist/chunks/menu-MTPSLDHZ.ts.map +7 -0
  12. package/dist/chunks/{tools-6P7EUX37.js → tools-OVNH45IJ.ts} +17 -59
  13. package/dist/chunks/tools-OVNH45IJ.ts.map +7 -0
  14. package/dist/index.ts +18 -42
  15. package/dist/index.ts.map +2 -2
  16. package/package.json +54 -55
  17. package/src/browser-manager.ts +872 -942
  18. package/src/browser-settings-menu.ts +315 -350
  19. package/src/cdp-client.ts +381 -398
  20. package/src/chrome-devtools.ts +205 -232
  21. package/src/display.ts +26 -29
  22. package/src/lazy-tools.ts +158 -181
  23. package/src/menu.ts +409 -446
  24. package/src/render.ts +72 -81
  25. package/src/runtime.ts +137 -140
  26. package/src/screenshot.ts +170 -186
  27. package/src/settings.ts +472 -523
  28. package/src/tool-names.ts +8 -14
  29. package/src/tool-selector.ts +242 -271
  30. package/src/tools.ts +218 -226
  31. package/src/webmcp/discovery.ts +184 -188
  32. package/src/webmcp/policy.ts +296 -329
  33. package/src/webmcp/protocol.ts +324 -337
  34. package/src/webmcp/tools.ts +136 -147
  35. package/dist/chunks/browser-settings-menu-IMB6HXSU.js.map +0 -7
  36. package/dist/chunks/chunk-GTTYS5GT.js.map +0 -7
  37. package/dist/chunks/chunk-LLXOCRNF.js.map +0 -7
  38. package/dist/chunks/chunk-SRT3UUIP.js.map +0 -7
  39. package/dist/chunks/menu-UJETYMSB.js.map +0 -7
  40. package/dist/chunks/tools-6P7EUX37.js.map +0 -7
package/src/render.ts CHANGED
@@ -4,117 +4,108 @@ import { sanitizeChromeDevtoolsDisplay } from "./display.js";
4
4
 
5
5
  const STATUS_KEY = "chrome-devtools";
6
6
  interface StatusContext {
7
- sessionManager: object;
8
- ui: { setStatus: (key: string, value: string | undefined) => void };
7
+ sessionManager: object;
8
+ ui: { setStatus: (key: string, value: string | undefined) => void };
9
9
  }
10
10
  interface RenderTheme {
11
- bold(text: string): string;
12
- fg(color: string, text: string): string;
11
+ bold(text: string): string;
12
+ fg(color: string, text: string): string;
13
13
  }
14
14
  const activeStatuses = new WeakMap<object, Array<{ status: string; token: symbol }>>();
15
15
 
16
16
  interface RenderComponent {
17
- invalidate(): void;
18
- render(width: number): string[];
17
+ invalidate(): void;
18
+ render(width: number): string[];
19
19
  }
20
20
 
21
21
  export function renderToolCall(action: string) {
22
- return () => new PiTextComponent(`Chrome DevTools: ${action}`);
22
+ return () => new PiTextComponent(`Chrome DevTools: ${action}`);
23
23
  }
24
24
 
25
25
  export function renderTextResult(
26
- result: AgentToolResult<unknown>,
27
- options: ToolRenderResultOptions,
28
- theme: RenderTheme,
26
+ result: AgentToolResult<unknown>,
27
+ options: ToolRenderResultOptions,
28
+ theme: RenderTheme,
29
29
  ) {
30
- const output = formatCollapsibleOutput(textContent(result), options);
31
- return new PiTextComponent(output.text, theme, output.color);
30
+ const output = formatCollapsibleOutput(textContent(result), options);
31
+ return new PiTextComponent(output.text, theme, output.color);
32
32
  }
33
33
 
34
34
  export function renderScreenshotResult(
35
- result: AgentToolResult<unknown>,
36
- options: ToolRenderResultOptions,
37
- theme: RenderTheme,
35
+ result: AgentToolResult<unknown>,
36
+ options: ToolRenderResultOptions,
37
+ theme: RenderTheme,
38
38
  ): RenderComponent {
39
- const output = formatCollapsibleOutput(screenshotTextContent(result), options);
40
- return new PiTextComponent(output.text, theme, output.color);
39
+ const output = formatCollapsibleOutput(screenshotTextContent(result), options);
40
+ return new PiTextComponent(output.text, theme, output.color);
41
41
  }
42
42
 
43
43
  function textContent(result: AgentToolResult<unknown>) {
44
- return result.content
45
- .flatMap((content) => (content.type === "text" ? [content.text] : []))
46
- .join("\n");
44
+ return result.content.flatMap((content) => (content.type === "text" ? [content.text] : [])).join("\n");
47
45
  }
48
46
 
49
47
  function screenshotTextContent(result: AgentToolResult<unknown>) {
50
- const text = textContent(result);
51
- if (text.trim()) return text;
48
+ const text = textContent(result);
49
+ if (text.trim()) return text;
52
50
 
53
- const details = result.details as { savedPath?: unknown; bytes?: unknown } | undefined;
54
- if (typeof details?.savedPath !== "string") return text;
55
- const bytes = typeof details.bytes === "number" ? ` (${details.bytes} bytes)` : "";
56
- return `Saved screenshot to ${details.savedPath}${bytes}`;
51
+ const details = result.details as { savedPath?: unknown; bytes?: unknown } | undefined;
52
+ if (typeof details?.savedPath !== "string") return text;
53
+ const bytes = typeof details.bytes === "number" ? ` (${details.bytes} bytes)` : "";
54
+ return `Saved screenshot to ${details.savedPath}${bytes}`;
57
55
  }
58
56
 
59
- function formatCollapsibleOutput(
60
- text: string,
61
- options: ToolRenderResultOptions,
62
- ): { text: string; color?: string } {
63
- if (options.isPartial) return { text: "Running...", color: "warning" };
64
- if (options.expanded) return { text, color: "toolOutput" };
57
+ function formatCollapsibleOutput(text: string, options: ToolRenderResultOptions): { text: string; color?: string } {
58
+ if (options.isPartial) return { text: "Running...", color: "warning" };
59
+ if (options.expanded) return { text, color: "toolOutput" };
65
60
 
66
- return { text: "" };
61
+ return { text: "" };
67
62
  }
68
63
 
69
64
  class PiTextComponent implements RenderComponent {
70
- private text: string;
71
- private readonly theme?: RenderTheme;
72
- private readonly color?: string;
73
-
74
- constructor(text = "", theme?: RenderTheme, color?: string) {
75
- this.text = text;
76
- this.theme = theme;
77
- this.color = color;
78
- }
79
-
80
- setText(text: string) {
81
- this.text = text;
82
- }
83
-
84
- invalidate() {
85
- // Stateless renderer: no cached layout to invalidate.
86
- }
87
-
88
- render(width: number) {
89
- const sanitizedText = sanitizeChromeDevtoolsDisplay(this.text);
90
- if (!sanitizedText.trim()) return [];
91
- return sanitizedText
92
- .replace(/\t/g, " ")
93
- .split(/\r?\n/)
94
- .map((line) => {
95
- const truncatedLine = truncateToWidth(line, Math.max(0, width), "");
96
- return this.theme && this.color ? this.theme.fg(this.color, truncatedLine) : truncatedLine;
97
- });
98
- }
65
+ private text: string;
66
+ private readonly theme?: RenderTheme;
67
+ private readonly color?: string;
68
+
69
+ constructor(text = "", theme?: RenderTheme, color?: string) {
70
+ this.text = text;
71
+ this.theme = theme;
72
+ this.color = color;
73
+ }
74
+
75
+ setText(text: string) {
76
+ this.text = text;
77
+ }
78
+
79
+ invalidate() {
80
+ // Stateless renderer: no cached layout to invalidate.
81
+ }
82
+
83
+ render(width: number) {
84
+ const sanitizedText = sanitizeChromeDevtoolsDisplay(this.text);
85
+ if (!sanitizedText.trim()) return [];
86
+ return sanitizedText
87
+ .replace(/\t/g, " ")
88
+ .split(/\r?\n/)
89
+ .map((line) => {
90
+ const truncatedLine = truncateToWidth(line, Math.max(0, width), "");
91
+ return this.theme && this.color ? this.theme.fg(this.color, truncatedLine) : truncatedLine;
92
+ });
93
+ }
99
94
  }
100
95
 
101
- export async function withStatus<T>(
102
- ctx: StatusContext,
103
- status: string,
104
- callback: () => Promise<T>,
105
- ) {
106
- const token = Symbol(status);
107
- const statuses = activeStatuses.get(ctx.sessionManager) ?? [];
108
- statuses.push({ status, token });
109
- activeStatuses.set(ctx.sessionManager, statuses);
110
- ctx.ui.setStatus(STATUS_KEY, status);
111
- try {
112
- return await callback();
113
- } finally {
114
- const index = statuses.findIndex((entry) => entry.token === token);
115
- if (index >= 0) statuses.splice(index, 1);
116
- const remaining = statuses.at(-1)?.status;
117
- if (statuses.length === 0) activeStatuses.delete(ctx.sessionManager);
118
- ctx.ui.setStatus(STATUS_KEY, remaining);
119
- }
96
+ export async function withStatus<T>(ctx: StatusContext, status: string, callback: () => Promise<T>) {
97
+ const token = Symbol(status);
98
+ const statuses = activeStatuses.get(ctx.sessionManager) ?? [];
99
+ statuses.push({ status, token });
100
+ activeStatuses.set(ctx.sessionManager, statuses);
101
+ ctx.ui.setStatus(STATUS_KEY, status);
102
+ try {
103
+ return await callback();
104
+ } finally {
105
+ const index = statuses.findIndex((entry) => entry.token === token);
106
+ if (index >= 0) statuses.splice(index, 1);
107
+ const remaining = statuses.at(-1)?.status;
108
+ if (statuses.length === 0) activeStatuses.delete(ctx.sessionManager);
109
+ ctx.ui.setStatus(STATUS_KEY, remaining);
110
+ }
120
111
  }
package/src/runtime.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import type { ChildProcess } from "node:child_process";
2
2
  import {
3
- DEFAULT_BROWSER_HOST,
4
- DEFAULT_BROWSER_PORT,
5
- type EffectiveBrowserSettings,
6
- parseConfiguredPort,
3
+ DEFAULT_BROWSER_HOST,
4
+ DEFAULT_BROWSER_PORT,
5
+ type EffectiveBrowserSettings,
6
+ parseConfiguredPort,
7
7
  } from "./settings.js";
8
8
 
9
9
  export const DEFAULT_HOST = DEFAULT_BROWSER_HOST;
@@ -17,197 +17,194 @@ export const DEVTOOLS_ACTIVE_PORT_FILE = "DevToolsActivePort";
17
17
  export const BROWSER_SHUTDOWN_WAIT_MS = 1_500;
18
18
 
19
19
  export interface DevToolsPage {
20
- id: string;
21
- type: string;
22
- title: string;
23
- url: string;
24
- webSocketDebuggerUrl?: string;
20
+ id: string;
21
+ type: string;
22
+ title: string;
23
+ url: string;
24
+ webSocketDebuggerUrl?: string;
25
25
  }
26
26
 
27
27
  export interface ChromeDevToolsState {
28
- host: string;
29
- port: number;
30
- configuredPort: number;
31
- hostConfigured: boolean;
32
- portConfigured: boolean;
33
- autoLaunchEnabled: boolean;
34
- endpointSource: EffectiveBrowserSettings["endpointSource"];
35
- autoLaunchSource: EffectiveBrowserSettings["autoLaunchSource"];
36
- browserExecutable?: string;
37
- extensionPaths: string[];
38
- browserExecutableSource: EffectiveBrowserSettings["executablePathSource"];
39
- extensionPathsSource: EffectiveBrowserSettings["extensionPathsSource"];
40
- settingsFilePath?: string;
41
- projectSettingsFilePath?: string;
42
- projectSettingsTrusted: boolean;
43
- activePageId?: string;
44
- managedBrowser?: ManagedBrowser;
45
- launchPromise?: Promise<void>;
46
- lastLaunchAttempt?: BrowserLaunchAttempt;
47
- shuttingDown: boolean;
48
- sessionGeneration: number;
49
- sessionController: AbortController;
50
- settingsNotice?: string;
28
+ host: string;
29
+ port: number;
30
+ configuredPort: number;
31
+ hostConfigured: boolean;
32
+ portConfigured: boolean;
33
+ autoLaunchEnabled: boolean;
34
+ endpointSource: EffectiveBrowserSettings["endpointSource"];
35
+ autoLaunchSource: EffectiveBrowserSettings["autoLaunchSource"];
36
+ browserExecutable?: string;
37
+ extensionPaths: string[];
38
+ browserExecutableSource: EffectiveBrowserSettings["executablePathSource"];
39
+ extensionPathsSource: EffectiveBrowserSettings["extensionPathsSource"];
40
+ settingsFilePath?: string;
41
+ projectSettingsFilePath?: string;
42
+ projectSettingsTrusted: boolean;
43
+ activePageId?: string;
44
+ managedBrowser?: ManagedBrowser;
45
+ launchPromise?: Promise<void>;
46
+ lastLaunchAttempt?: BrowserLaunchAttempt;
47
+ shuttingDown: boolean;
48
+ sessionGeneration: number;
49
+ sessionController: AbortController;
50
+ settingsNotice?: string;
51
51
  }
52
52
 
53
53
  export interface ManagedBrowser {
54
- process: ChildProcess;
55
- userDataDir: string;
56
- port?: number;
57
- exited: boolean;
58
- ready: boolean;
59
- ownerGeneration: number;
60
- sessionOwner?: object;
61
- cleanupPromise?: Promise<void>;
54
+ process: ChildProcess;
55
+ userDataDir: string;
56
+ port?: number;
57
+ exited: boolean;
58
+ ready: boolean;
59
+ ownerGeneration: number;
60
+ sessionOwner?: object;
61
+ cleanupPromise?: Promise<void>;
62
62
  }
63
63
 
64
64
  export interface BrowserLaunchAttempt {
65
- candidateLabels: string[];
66
- mode: "dynamic-port" | "explicit-port";
67
- selectedCandidate?: string;
68
- userDataDir?: string;
69
- lastError?: string;
65
+ candidateLabels: string[];
66
+ mode: "dynamic-port" | "explicit-port";
67
+ selectedCandidate?: string;
68
+ userDataDir?: string;
69
+ lastError?: string;
70
70
  }
71
71
 
72
72
  export interface BrowserCandidateDefinition {
73
- label: string;
74
- executable: string;
75
- source: "env" | "path" | "wellKnownPath";
73
+ label: string;
74
+ executable: string;
75
+ source: "env" | "path" | "wellKnownPath";
76
76
  }
77
77
 
78
78
  export interface BrowserCandidate extends BrowserCandidateDefinition {
79
- resolvedExecutable: string;
79
+ resolvedExecutable: string;
80
80
  }
81
81
 
82
82
  export { parseConfiguredPort };
83
83
 
84
84
  export const state: ChromeDevToolsState = {
85
- host: DEFAULT_HOST,
86
- port: DEFAULT_PORT,
87
- configuredPort: DEFAULT_PORT,
88
- hostConfigured: false,
89
- portConfigured: false,
90
- autoLaunchEnabled: true,
91
- endpointSource: "default",
92
- autoLaunchSource: "default",
93
- extensionPaths: [],
94
- browserExecutableSource: "default",
95
- extensionPathsSource: "default",
96
- projectSettingsTrusted: false,
97
- shuttingDown: false,
98
- sessionGeneration: 0,
99
- sessionController: new AbortController(),
85
+ host: DEFAULT_HOST,
86
+ port: DEFAULT_PORT,
87
+ configuredPort: DEFAULT_PORT,
88
+ hostConfigured: false,
89
+ portConfigured: false,
90
+ autoLaunchEnabled: true,
91
+ endpointSource: "default",
92
+ autoLaunchSource: "default",
93
+ extensionPaths: [],
94
+ browserExecutableSource: "default",
95
+ extensionPathsSource: "default",
96
+ projectSettingsTrusted: false,
97
+ shuttingDown: false,
98
+ sessionGeneration: 0,
99
+ sessionController: new AbortController(),
100
100
  };
101
101
 
102
102
  interface WebMcpSessionRuntime {
103
- controller: AbortController;
104
- enabled: boolean;
105
- controllers: Set<AbortController>;
106
- generation: number;
107
- sessionGeneration: number;
103
+ controller: AbortController;
104
+ enabled: boolean;
105
+ controllers: Set<AbortController>;
106
+ generation: number;
107
+ sessionGeneration: number;
108
108
  }
109
109
 
110
110
  const webMcpRuntimeByOwner = new WeakMap<object, WebMcpSessionRuntime>();
111
111
 
112
112
  export function setWebMcpSessionOwner(owner: object) {
113
- const runtime = webMcpRuntime(owner);
114
- runtime.enabled = false;
115
- runtime.sessionGeneration += 1;
113
+ const runtime = webMcpRuntime(owner);
114
+ runtime.enabled = false;
115
+ runtime.sessionGeneration += 1;
116
116
  }
117
117
 
118
118
  export function beginWebMcpOperation(owner: object, toolSignal?: AbortSignal) {
119
- const runtime = webMcpRuntime(owner);
120
- const controller = new AbortController();
121
- runtime.controllers.add(controller);
122
- const signals = [controller.signal, runtime.controller.signal];
123
- if (toolSignal) signals.push(toolSignal);
124
- const signal = AbortSignal.any(signals);
125
- return {
126
- signal,
127
- owner,
128
- sessionGeneration: runtime.sessionGeneration,
129
- webMcpGeneration: runtime.generation,
130
- dispose() {
131
- runtime.controllers.delete(controller);
132
- },
133
- };
119
+ const runtime = webMcpRuntime(owner);
120
+ const controller = new AbortController();
121
+ runtime.controllers.add(controller);
122
+ const signals = [controller.signal, runtime.controller.signal];
123
+ if (toolSignal) signals.push(toolSignal);
124
+ const signal = AbortSignal.any(signals);
125
+ return {
126
+ signal,
127
+ owner,
128
+ sessionGeneration: runtime.sessionGeneration,
129
+ webMcpGeneration: runtime.generation,
130
+ dispose() {
131
+ runtime.controllers.delete(controller);
132
+ },
133
+ };
134
134
  }
135
135
 
136
136
  export function invalidateWebMcpOperations(owner: object, reason: string) {
137
- const runtime = webMcpRuntime(owner);
138
- runtime.generation += 1;
139
- const controllers = [...runtime.controllers];
140
- runtime.controllers.clear();
141
- const error = new DOMException(reason, "AbortError");
142
- runtime.controller.abort(error);
143
- runtime.controller = new AbortController();
144
- for (const controller of controllers) controller.abort(error);
137
+ const runtime = webMcpRuntime(owner);
138
+ runtime.generation += 1;
139
+ const controllers = [...runtime.controllers];
140
+ runtime.controllers.clear();
141
+ const error = new DOMException(reason, "AbortError");
142
+ runtime.controller.abort(error);
143
+ runtime.controller = new AbortController();
144
+ for (const controller of controllers) controller.abort(error);
145
145
  }
146
146
 
147
147
  export function currentWebMcpGeneration(owner: object) {
148
- return webMcpRuntime(owner).generation;
148
+ return webMcpRuntime(owner).generation;
149
149
  }
150
150
 
151
151
  export function webMcpSessionSignal(owner: object) {
152
- return webMcpRuntime(owner).controller.signal;
152
+ return webMcpRuntime(owner).controller.signal;
153
153
  }
154
154
 
155
155
  export function applyRuntimeWebMcpSetting(enabled: boolean, owner: object) {
156
- const runtime = webMcpRuntime(owner);
157
- if (runtime.enabled !== enabled) {
158
- invalidateWebMcpOperations(owner, `WebMCP ${enabled ? "enabled" : "disabled"}`);
159
- }
160
- runtime.enabled = enabled;
156
+ const runtime = webMcpRuntime(owner);
157
+ if (runtime.enabled !== enabled) {
158
+ invalidateWebMcpOperations(owner, `WebMCP ${enabled ? "enabled" : "disabled"}`);
159
+ }
160
+ runtime.enabled = enabled;
161
161
  }
162
162
 
163
163
  export function webMcpEnabled(owner: object) {
164
- return webMcpRuntime(owner).enabled;
164
+ return webMcpRuntime(owner).enabled;
165
165
  }
166
166
 
167
167
  export function webMcpOperationIsCurrent(operation: {
168
- owner: object;
169
- sessionGeneration: number;
170
- webMcpGeneration: number;
168
+ owner: object;
169
+ sessionGeneration: number;
170
+ webMcpGeneration: number;
171
171
  }) {
172
- const runtime = webMcpRuntime(operation.owner);
173
- return (
174
- operation.sessionGeneration === runtime.sessionGeneration &&
175
- operation.webMcpGeneration === runtime.generation
176
- );
172
+ const runtime = webMcpRuntime(operation.owner);
173
+ return operation.sessionGeneration === runtime.sessionGeneration && operation.webMcpGeneration === runtime.generation;
177
174
  }
178
175
 
179
176
  function webMcpRuntime(owner: object) {
180
- const existing = webMcpRuntimeByOwner.get(owner);
181
- if (existing) return existing;
182
- const created: WebMcpSessionRuntime = {
183
- controller: new AbortController(),
184
- controllers: new Set(),
185
- enabled: false,
186
- generation: 0,
187
- sessionGeneration: 0,
188
- };
189
- webMcpRuntimeByOwner.set(owner, created);
190
- return created;
177
+ const existing = webMcpRuntimeByOwner.get(owner);
178
+ if (existing) return existing;
179
+ const created: WebMcpSessionRuntime = {
180
+ controller: new AbortController(),
181
+ controllers: new Set(),
182
+ enabled: false,
183
+ generation: 0,
184
+ sessionGeneration: 0,
185
+ };
186
+ webMcpRuntimeByOwner.set(owner, created);
187
+ return created;
191
188
  }
192
189
 
193
190
  export function applyRuntimeBrowserSettings(
194
- browser: EffectiveBrowserSettings,
195
- paths: { user: string; project?: string },
196
- projectTrusted: boolean,
191
+ browser: EffectiveBrowserSettings,
192
+ paths: { user: string; project?: string },
193
+ projectTrusted: boolean,
197
194
  ) {
198
- state.host = browser.host;
199
- state.port = browser.port;
200
- state.configuredPort = browser.port;
201
- state.hostConfigured = browser.hostConfigured;
202
- state.portConfigured = browser.portConfigured;
203
- state.autoLaunchEnabled = browser.autoLaunchEnabled;
204
- state.endpointSource = browser.endpointSource;
205
- state.autoLaunchSource = browser.autoLaunchSource;
206
- state.browserExecutable = browser.executablePath;
207
- state.extensionPaths = [...browser.extensionPaths];
208
- state.browserExecutableSource = browser.executablePathSource;
209
- state.extensionPathsSource = browser.extensionPathsSource;
210
- state.settingsFilePath = paths.user;
211
- state.projectSettingsFilePath = paths.project;
212
- state.projectSettingsTrusted = projectTrusted;
195
+ state.host = browser.host;
196
+ state.port = browser.port;
197
+ state.configuredPort = browser.port;
198
+ state.hostConfigured = browser.hostConfigured;
199
+ state.portConfigured = browser.portConfigured;
200
+ state.autoLaunchEnabled = browser.autoLaunchEnabled;
201
+ state.endpointSource = browser.endpointSource;
202
+ state.autoLaunchSource = browser.autoLaunchSource;
203
+ state.browserExecutable = browser.executablePath;
204
+ state.extensionPaths = [...browser.extensionPaths];
205
+ state.browserExecutableSource = browser.executablePathSource;
206
+ state.extensionPathsSource = browser.extensionPathsSource;
207
+ state.settingsFilePath = paths.user;
208
+ state.projectSettingsFilePath = paths.project;
209
+ state.projectSettingsTrusted = projectTrusted;
213
210
  }