@diegosouzacdv/jev-browser-mcp 0.2.0 → 0.3.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 +315 -1775
- package/config/ui-testing.json +45 -40
- package/docs/jev-browser-mcp.md +354 -291
- package/mcp_servers/jev-browser-npm/src/accessibility.mjs +38 -0
- package/mcp_servers/jev-browser-npm/src/config.mjs +151 -141
- package/mcp_servers/jev-browser-npm/src/flow.mjs +990 -769
- package/mcp_servers/jev-browser-npm/src/server.mjs +12 -12
- package/package.json +32 -34
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { JevBrowserError } from "./config.mjs";
|
|
2
|
+
|
|
3
|
+
export const ACCESSIBILITY_STANDARDS = Object.freeze({
|
|
4
|
+
wcag2aa: Object.freeze(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]),
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
export async function runAccessibilityAudit(page, standard, settings) {
|
|
8
|
+
const tags = ACCESSIBILITY_STANDARDS[standard];
|
|
9
|
+
if (!tags) throw new JevBrowserError("audit_accessibility standard must be wcag2aa");
|
|
10
|
+
|
|
11
|
+
let AxeBuilder;
|
|
12
|
+
try {
|
|
13
|
+
({ default: AxeBuilder } = await import("@axe-core/playwright"));
|
|
14
|
+
} catch {
|
|
15
|
+
throw new JevBrowserError("accessibility auditing requires the installed @axe-core/playwright dependency");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let results;
|
|
19
|
+
try {
|
|
20
|
+
results = await new AxeBuilder({ page }).withTags([...tags]).analyze();
|
|
21
|
+
} catch {
|
|
22
|
+
throw new JevBrowserError("axe-core could not complete the accessibility audit");
|
|
23
|
+
}
|
|
24
|
+
const violations = Array.isArray(results?.violations) ? results.violations : [];
|
|
25
|
+
const incomplete = Array.isArray(results?.incomplete) ? results.incomplete : [];
|
|
26
|
+
return {
|
|
27
|
+
standard,
|
|
28
|
+
violations_count: violations.length,
|
|
29
|
+
violations_truncated: violations.length > settings.jev.maxAccessibilityViolations,
|
|
30
|
+
violations: violations.slice(0, settings.jev.maxAccessibilityViolations).map((violation) => ({
|
|
31
|
+
id: String(violation.id || "unknown").slice(0, 100),
|
|
32
|
+
impact: ["minor", "moderate", "serious", "critical"].includes(violation.impact) ? violation.impact : null,
|
|
33
|
+
help: String(violation.help || "").slice(0, settings.jev.maxDiagnosticChars),
|
|
34
|
+
nodes_count: Array.isArray(violation.nodes) ? violation.nodes.length : 0,
|
|
35
|
+
})),
|
|
36
|
+
incomplete_count: incomplete.length,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -4,39 +4,43 @@ import path from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
|
|
6
6
|
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../..");
|
|
7
|
-
const CONFIG_PATH = path.join(PACKAGE_ROOT, "config", "ui-testing.json");
|
|
8
|
-
const CONFIG_KEYS = {
|
|
9
|
-
root: ["version", "browser", "jev", "jev_browser_mcp"],
|
|
10
|
-
browser: [
|
|
7
|
+
const CONFIG_PATH = path.join(PACKAGE_ROOT, "config", "ui-testing.json");
|
|
8
|
+
const CONFIG_KEYS = {
|
|
9
|
+
root: ["version", "browser", "jev", "jev_browser_mcp"],
|
|
10
|
+
browser: [
|
|
11
11
|
"mode",
|
|
12
12
|
"harness_browser",
|
|
13
13
|
"computer_browser",
|
|
14
14
|
"playwright_mcp_package",
|
|
15
|
-
"computer_user_data_dir",
|
|
16
|
-
"max_flow_steps",
|
|
17
|
-
"max_text_entry_chars",
|
|
18
|
-
],
|
|
19
|
-
nodeBrowser: [
|
|
20
|
-
"max_action_timeout_seconds",
|
|
21
|
-
"max_upload_files",
|
|
22
|
-
"max_upload_path_chars",
|
|
23
|
-
"max_upload_file_bytes",
|
|
24
|
-
"max_upload_total_bytes",
|
|
25
|
-
"upload_root_env",
|
|
26
|
-
"artifact_directory",
|
|
27
|
-
"artifact_directory_env",
|
|
28
|
-
"max_frame_snapshots",
|
|
29
|
-
"fast_path_single_plan_default",
|
|
30
|
-
"screenshot_on_failure_default",
|
|
31
|
-
"trace_on_failure_default",
|
|
32
|
-
"capture_console_errors_default",
|
|
33
|
-
"capture_network_errors_default",
|
|
34
|
-
"block_trackers_default",
|
|
35
|
-
"snapshot_scope_default",
|
|
36
|
-
"tracker_host_suffixes",
|
|
37
|
-
"blocked_resource_types",
|
|
15
|
+
"computer_user_data_dir",
|
|
16
|
+
"max_flow_steps",
|
|
17
|
+
"max_text_entry_chars",
|
|
38
18
|
],
|
|
39
|
-
|
|
19
|
+
nodeBrowser: [
|
|
20
|
+
"max_action_timeout_seconds",
|
|
21
|
+
"max_upload_files",
|
|
22
|
+
"max_upload_path_chars",
|
|
23
|
+
"max_upload_file_bytes",
|
|
24
|
+
"max_upload_total_bytes",
|
|
25
|
+
"max_download_files",
|
|
26
|
+
"max_download_file_bytes",
|
|
27
|
+
"max_download_total_bytes",
|
|
28
|
+
"max_download_timeout_seconds",
|
|
29
|
+
"upload_root_env",
|
|
30
|
+
"artifact_directory",
|
|
31
|
+
"artifact_directory_env",
|
|
32
|
+
"max_frame_snapshots",
|
|
33
|
+
"fast_path_single_plan_default",
|
|
34
|
+
"screenshot_on_failure_default",
|
|
35
|
+
"trace_on_failure_default",
|
|
36
|
+
"capture_console_errors_default",
|
|
37
|
+
"capture_network_errors_default",
|
|
38
|
+
"block_trackers_default",
|
|
39
|
+
"snapshot_scope_default",
|
|
40
|
+
"tracker_host_suffixes",
|
|
41
|
+
"blocked_resource_types",
|
|
42
|
+
],
|
|
43
|
+
jev: [
|
|
40
44
|
"provider_url",
|
|
41
45
|
"credential_env",
|
|
42
46
|
"model",
|
|
@@ -44,12 +48,13 @@ const CONFIG_KEYS = {
|
|
|
44
48
|
"max_flow_chars",
|
|
45
49
|
"max_snapshot_chars",
|
|
46
50
|
"max_action_count",
|
|
47
|
-
"max_action_description_chars",
|
|
48
|
-
"max_response_bytes",
|
|
49
|
-
],
|
|
50
|
-
nodeJev: [
|
|
51
|
-
"max_diagnostic_items",
|
|
52
|
-
"max_diagnostic_chars",
|
|
51
|
+
"max_action_description_chars",
|
|
52
|
+
"max_response_bytes",
|
|
53
|
+
],
|
|
54
|
+
nodeJev: [
|
|
55
|
+
"max_diagnostic_items",
|
|
56
|
+
"max_diagnostic_chars",
|
|
57
|
+
"max_accessibility_violations",
|
|
53
58
|
],
|
|
54
59
|
};
|
|
55
60
|
|
|
@@ -73,52 +78,52 @@ function requireKeys(value, keys, scope) {
|
|
|
73
78
|
}
|
|
74
79
|
}
|
|
75
80
|
|
|
76
|
-
function positiveNumber(value, name, integer = false) {
|
|
81
|
+
function positiveNumber(value, name, integer = false) {
|
|
77
82
|
const parsed = Number(value);
|
|
78
83
|
if (!Number.isFinite(parsed) || parsed <= 0 || (integer && !Number.isInteger(parsed))) {
|
|
79
84
|
throw new JevBrowserError(`config/ui-testing.json ${name} must be a positive ${integer ? "integer" : "number"}`);
|
|
80
85
|
}
|
|
81
86
|
return parsed;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function expandHomeDirectory(value) {
|
|
85
|
-
if (value.startsWith("~/") || value.startsWith("~\\")) return path.join(homedir(), value.slice(2));
|
|
86
|
-
return value;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function requireOutsidePackage(resolved, name) {
|
|
90
|
-
const insidePackage = path.relative(PACKAGE_ROOT, resolved);
|
|
91
|
-
if (insidePackage === "" || (!insidePackage.startsWith(`..${path.sep}`) && insidePackage !== ".." && !path.isAbsolute(insidePackage))) {
|
|
92
|
-
throw new JevBrowserError(`${name} must be outside the installed package directory`);
|
|
93
|
-
}
|
|
94
|
-
return resolved;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function configuredDirectory(value, name) {
|
|
98
|
-
if (typeof value !== "string" || !value.trim()) throw new JevBrowserError(`config/ui-testing.json ${name} must be a directory path`);
|
|
99
|
-
const expanded = expandHomeDirectory(value.trim());
|
|
100
|
-
if (!path.isAbsolute(expanded)) throw new JevBrowserError(`config/ui-testing.json ${name} must be absolute or start with ~`);
|
|
101
|
-
return path.resolve(expanded);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function environmentName(value, name) {
|
|
105
|
-
if (typeof value !== "string" || !/^[A-Z][A-Z0-9_]*$/.test(value)) {
|
|
106
|
-
throw new JevBrowserError(`config/ui-testing.json ${name} must be an environment variable name`);
|
|
107
|
-
}
|
|
108
|
-
return value;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function booleanValue(value, name) {
|
|
112
|
-
if (typeof value !== "boolean") throw new JevBrowserError(`config/ui-testing.json ${name} must be a boolean`);
|
|
113
|
-
return value;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function stringList(value, name, validator = () => true) {
|
|
117
|
-
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !item.trim() || !validator(item))) {
|
|
118
|
-
throw new JevBrowserError(`config/ui-testing.json ${name} must be an array of valid strings`);
|
|
119
|
-
}
|
|
120
|
-
return value.map((item) => item.trim());
|
|
121
|
-
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function expandHomeDirectory(value) {
|
|
90
|
+
if (value.startsWith("~/") || value.startsWith("~\\")) return path.join(homedir(), value.slice(2));
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function requireOutsidePackage(resolved, name) {
|
|
95
|
+
const insidePackage = path.relative(PACKAGE_ROOT, resolved);
|
|
96
|
+
if (insidePackage === "" || (!insidePackage.startsWith(`..${path.sep}`) && insidePackage !== ".." && !path.isAbsolute(insidePackage))) {
|
|
97
|
+
throw new JevBrowserError(`${name} must be outside the installed package directory`);
|
|
98
|
+
}
|
|
99
|
+
return resolved;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function configuredDirectory(value, name) {
|
|
103
|
+
if (typeof value !== "string" || !value.trim()) throw new JevBrowserError(`config/ui-testing.json ${name} must be a directory path`);
|
|
104
|
+
const expanded = expandHomeDirectory(value.trim());
|
|
105
|
+
if (!path.isAbsolute(expanded)) throw new JevBrowserError(`config/ui-testing.json ${name} must be absolute or start with ~`);
|
|
106
|
+
return path.resolve(expanded);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function environmentName(value, name) {
|
|
110
|
+
if (typeof value !== "string" || !/^[A-Z][A-Z0-9_]*$/.test(value)) {
|
|
111
|
+
throw new JevBrowserError(`config/ui-testing.json ${name} must be an environment variable name`);
|
|
112
|
+
}
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function booleanValue(value, name) {
|
|
117
|
+
if (typeof value !== "boolean") throw new JevBrowserError(`config/ui-testing.json ${name} must be a boolean`);
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function stringList(value, name, validator = () => true) {
|
|
122
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !item.trim() || !validator(item))) {
|
|
123
|
+
throw new JevBrowserError(`config/ui-testing.json ${name} must be an array of valid strings`);
|
|
124
|
+
}
|
|
125
|
+
return value.map((item) => item.trim());
|
|
126
|
+
}
|
|
122
127
|
|
|
123
128
|
function validProviderUrl(value) {
|
|
124
129
|
let parsed;
|
|
@@ -133,10 +138,10 @@ function validProviderUrl(value) {
|
|
|
133
138
|
return parsed.toString();
|
|
134
139
|
}
|
|
135
140
|
|
|
136
|
-
function profileDirectory(template, channel, override) {
|
|
137
|
-
const value = expandHomeDirectory(override?.trim() || template.replace("{browser}", channel));
|
|
138
|
-
if (!path.isAbsolute(value)) throw new JevBrowserError("JEV_BROWSER_PROFILE must be an absolute path");
|
|
139
|
-
return requireOutsidePackage(path.resolve(value), "browser profile");
|
|
141
|
+
function profileDirectory(template, channel, override) {
|
|
142
|
+
const value = expandHomeDirectory(override?.trim() || template.replace("{browser}", channel));
|
|
143
|
+
if (!path.isAbsolute(value)) throw new JevBrowserError("JEV_BROWSER_PROFILE must be an absolute path");
|
|
144
|
+
return requireOutsidePackage(path.resolve(value), "browser profile");
|
|
140
145
|
}
|
|
141
146
|
|
|
142
147
|
export function loadSettings({ env = process.env, configPath = CONFIG_PATH } = {}) {
|
|
@@ -146,14 +151,14 @@ export function loadSettings({ env = process.env, configPath = CONFIG_PATH } = {
|
|
|
146
151
|
} catch {
|
|
147
152
|
throw new JevBrowserError("config/ui-testing.json is unreadable or invalid JSON");
|
|
148
153
|
}
|
|
149
|
-
requireKeys(document, CONFIG_KEYS.root, "root");
|
|
150
|
-
requireKeys(document.browser, CONFIG_KEYS.browser, "browser");
|
|
151
|
-
requireKeys(document.jev, CONFIG_KEYS.jev, "jev");
|
|
152
|
-
requireKeys(document.jev_browser_mcp, ["browser", "jev"], "jev_browser_mcp");
|
|
153
|
-
requireKeys(document.jev_browser_mcp.browser, CONFIG_KEYS.nodeBrowser, "jev_browser_mcp.browser");
|
|
154
|
-
requireKeys(document.jev_browser_mcp.jev, CONFIG_KEYS.nodeJev, "jev_browser_mcp.jev");
|
|
155
|
-
const browserOptions = document.jev_browser_mcp.browser;
|
|
156
|
-
const jevOptions = document.jev_browser_mcp.jev;
|
|
154
|
+
requireKeys(document, CONFIG_KEYS.root, "root");
|
|
155
|
+
requireKeys(document.browser, CONFIG_KEYS.browser, "browser");
|
|
156
|
+
requireKeys(document.jev, CONFIG_KEYS.jev, "jev");
|
|
157
|
+
requireKeys(document.jev_browser_mcp, ["browser", "jev"], "jev_browser_mcp");
|
|
158
|
+
requireKeys(document.jev_browser_mcp.browser, CONFIG_KEYS.nodeBrowser, "jev_browser_mcp.browser");
|
|
159
|
+
requireKeys(document.jev_browser_mcp.jev, CONFIG_KEYS.nodeJev, "jev_browser_mcp.jev");
|
|
160
|
+
const browserOptions = document.jev_browser_mcp.browser;
|
|
161
|
+
const jevOptions = document.jev_browser_mcp.jev;
|
|
157
162
|
if (document.version !== 1) throw new JevBrowserError("config/ui-testing.json has an unsupported version");
|
|
158
163
|
|
|
159
164
|
if (!new Set(["harness", "computer"]).has(document.browser.mode)) {
|
|
@@ -176,45 +181,45 @@ export function loadSettings({ env = process.env, configPath = CONFIG_PATH } = {
|
|
|
176
181
|
if (!new Set(["chrome", "msedge"]).has(channel)) {
|
|
177
182
|
throw new JevBrowserError("JEV_BROWSER_CHANNEL must be chrome or msedge");
|
|
178
183
|
}
|
|
179
|
-
const profileTemplate = document.browser.computer_user_data_dir;
|
|
184
|
+
const profileTemplate = document.browser.computer_user_data_dir;
|
|
180
185
|
const profileRemainder = typeof profileTemplate === "string" ? profileTemplate.replace("{browser}", "") : "";
|
|
181
186
|
if (typeof profileTemplate !== "string" || profileTemplate.split("{browser}").length !== 2
|
|
182
187
|
|| profileRemainder.includes("{") || profileRemainder.includes("}")) {
|
|
183
188
|
throw new JevBrowserError("config/ui-testing.json browser.computer_user_data_dir must contain {browser}");
|
|
184
189
|
}
|
|
185
190
|
|
|
186
|
-
const configuredProviderUrl = validProviderUrl(document.jev.provider_url);
|
|
191
|
+
const configuredProviderUrl = validProviderUrl(document.jev.provider_url);
|
|
187
192
|
const providerUrl = validProviderUrl(env.JEV_PROVIDER_URL?.trim() || configuredProviderUrl);
|
|
188
|
-
const credentialEnv = environmentName(document.jev.credential_env, "jev.credential_env");
|
|
193
|
+
const credentialEnv = environmentName(document.jev.credential_env, "jev.credential_env");
|
|
189
194
|
const configuredModel = String(document.jev.model || "").trim();
|
|
190
195
|
if (!configuredModel) throw new JevBrowserError("config/ui-testing.json jev.model is required");
|
|
191
|
-
const model = (env.JEV_MODEL?.trim() || configuredModel).trim();
|
|
192
|
-
if (!model) throw new JevBrowserError("Jev model must not be empty");
|
|
193
|
-
|
|
194
|
-
const artifactEnv = environmentName(browserOptions.artifact_directory_env, "jev_browser_mcp.browser.artifact_directory_env");
|
|
195
|
-
const artifactDirectory = requireOutsidePackage(configuredDirectory(
|
|
196
|
-
env[artifactEnv]?.trim() || browserOptions.artifact_directory,
|
|
197
|
-
"jev_browser_mcp.browser.artifact_directory",
|
|
198
|
-
), "browser artifact directory");
|
|
199
|
-
const uploadRootEnv = environmentName(browserOptions.upload_root_env, "jev_browser_mcp.browser.upload_root_env");
|
|
200
|
-
const configuredUploadRoot = env[uploadRootEnv]?.trim();
|
|
201
|
-
const uploadRoot = configuredUploadRoot
|
|
202
|
-
? configuredDirectory(configuredUploadRoot, `environment ${uploadRootEnv}`)
|
|
203
|
-
: null;
|
|
204
|
-
const snapshotScope = browserOptions.snapshot_scope_default;
|
|
205
|
-
if (!new Set(["body", "main", "dialog"]).has(snapshotScope)) {
|
|
206
|
-
throw new JevBrowserError("config/ui-testing.json jev_browser_mcp.browser.snapshot_scope_default must be body, main, or dialog");
|
|
207
|
-
}
|
|
208
|
-
const trackerHostSuffixes = stringList(
|
|
209
|
-
browserOptions.tracker_host_suffixes,
|
|
210
|
-
"jev_browser_mcp.browser.tracker_host_suffixes",
|
|
211
|
-
(host) => /^[a-z0-9.-]+$/i.test(host) && !host.startsWith(".") && !host.endsWith("."),
|
|
212
|
-
);
|
|
213
|
-
const blockedResourceTypes = stringList(
|
|
214
|
-
browserOptions.blocked_resource_types,
|
|
215
|
-
"jev_browser_mcp.browser.blocked_resource_types",
|
|
216
|
-
(type) => new Set(["font", "media", "image"]).has(type),
|
|
217
|
-
);
|
|
196
|
+
const model = (env.JEV_MODEL?.trim() || configuredModel).trim();
|
|
197
|
+
if (!model) throw new JevBrowserError("Jev model must not be empty");
|
|
198
|
+
|
|
199
|
+
const artifactEnv = environmentName(browserOptions.artifact_directory_env, "jev_browser_mcp.browser.artifact_directory_env");
|
|
200
|
+
const artifactDirectory = requireOutsidePackage(configuredDirectory(
|
|
201
|
+
env[artifactEnv]?.trim() || browserOptions.artifact_directory,
|
|
202
|
+
"jev_browser_mcp.browser.artifact_directory",
|
|
203
|
+
), "browser artifact directory");
|
|
204
|
+
const uploadRootEnv = environmentName(browserOptions.upload_root_env, "jev_browser_mcp.browser.upload_root_env");
|
|
205
|
+
const configuredUploadRoot = env[uploadRootEnv]?.trim();
|
|
206
|
+
const uploadRoot = configuredUploadRoot
|
|
207
|
+
? configuredDirectory(configuredUploadRoot, `environment ${uploadRootEnv}`)
|
|
208
|
+
: null;
|
|
209
|
+
const snapshotScope = browserOptions.snapshot_scope_default;
|
|
210
|
+
if (!new Set(["body", "main", "dialog"]).has(snapshotScope)) {
|
|
211
|
+
throw new JevBrowserError("config/ui-testing.json jev_browser_mcp.browser.snapshot_scope_default must be body, main, or dialog");
|
|
212
|
+
}
|
|
213
|
+
const trackerHostSuffixes = stringList(
|
|
214
|
+
browserOptions.tracker_host_suffixes,
|
|
215
|
+
"jev_browser_mcp.browser.tracker_host_suffixes",
|
|
216
|
+
(host) => /^[a-z0-9.-]+$/i.test(host) && !host.startsWith(".") && !host.endsWith("."),
|
|
217
|
+
);
|
|
218
|
+
const blockedResourceTypes = stringList(
|
|
219
|
+
browserOptions.blocked_resource_types,
|
|
220
|
+
"jev_browser_mcp.browser.blocked_resource_types",
|
|
221
|
+
(type) => new Set(["font", "media", "image"]).has(type),
|
|
222
|
+
);
|
|
218
223
|
|
|
219
224
|
return Object.freeze({
|
|
220
225
|
env,
|
|
@@ -222,27 +227,31 @@ export function loadSettings({ env = process.env, configPath = CONFIG_PATH } = {
|
|
|
222
227
|
mode,
|
|
223
228
|
channel,
|
|
224
229
|
profileDir: profileDirectory(profileTemplate, channel, env.JEV_BROWSER_PROFILE),
|
|
225
|
-
maxFlowSteps: positiveNumber(document.browser.max_flow_steps, "browser.max_flow_steps", true),
|
|
226
|
-
maxTextEntryChars: positiveNumber(document.browser.max_text_entry_chars, "browser.max_text_entry_chars", true),
|
|
227
|
-
actionTimeoutMs: positiveNumber(browserOptions.max_action_timeout_seconds, "jev_browser_mcp.browser.max_action_timeout_seconds") * 1000,
|
|
228
|
-
maxUploadFiles: positiveNumber(browserOptions.max_upload_files, "jev_browser_mcp.browser.max_upload_files", true),
|
|
229
|
-
maxUploadPathChars: positiveNumber(browserOptions.max_upload_path_chars, "jev_browser_mcp.browser.max_upload_path_chars", true),
|
|
230
|
-
maxUploadFileBytes: positiveNumber(browserOptions.max_upload_file_bytes, "jev_browser_mcp.browser.max_upload_file_bytes", true),
|
|
231
|
-
maxUploadTotalBytes: positiveNumber(browserOptions.max_upload_total_bytes, "jev_browser_mcp.browser.max_upload_total_bytes", true),
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
230
|
+
maxFlowSteps: positiveNumber(document.browser.max_flow_steps, "browser.max_flow_steps", true),
|
|
231
|
+
maxTextEntryChars: positiveNumber(document.browser.max_text_entry_chars, "browser.max_text_entry_chars", true),
|
|
232
|
+
actionTimeoutMs: positiveNumber(browserOptions.max_action_timeout_seconds, "jev_browser_mcp.browser.max_action_timeout_seconds") * 1000,
|
|
233
|
+
maxUploadFiles: positiveNumber(browserOptions.max_upload_files, "jev_browser_mcp.browser.max_upload_files", true),
|
|
234
|
+
maxUploadPathChars: positiveNumber(browserOptions.max_upload_path_chars, "jev_browser_mcp.browser.max_upload_path_chars", true),
|
|
235
|
+
maxUploadFileBytes: positiveNumber(browserOptions.max_upload_file_bytes, "jev_browser_mcp.browser.max_upload_file_bytes", true),
|
|
236
|
+
maxUploadTotalBytes: positiveNumber(browserOptions.max_upload_total_bytes, "jev_browser_mcp.browser.max_upload_total_bytes", true),
|
|
237
|
+
maxDownloadFiles: positiveNumber(browserOptions.max_download_files, "jev_browser_mcp.browser.max_download_files", true),
|
|
238
|
+
maxDownloadFileBytes: positiveNumber(browserOptions.max_download_file_bytes, "jev_browser_mcp.browser.max_download_file_bytes", true),
|
|
239
|
+
maxDownloadTotalBytes: positiveNumber(browserOptions.max_download_total_bytes, "jev_browser_mcp.browser.max_download_total_bytes", true),
|
|
240
|
+
downloadTimeoutMs: positiveNumber(browserOptions.max_download_timeout_seconds, "jev_browser_mcp.browser.max_download_timeout_seconds") * 1000,
|
|
241
|
+
uploadRoot,
|
|
242
|
+
artifactDirectory,
|
|
243
|
+
maxFrameSnapshots: positiveNumber(browserOptions.max_frame_snapshots, "jev_browser_mcp.browser.max_frame_snapshots", true),
|
|
244
|
+
defaults: Object.freeze({
|
|
245
|
+
fastPath: booleanValue(browserOptions.fast_path_single_plan_default, "jev_browser_mcp.browser.fast_path_single_plan_default"),
|
|
246
|
+
screenshotOnFailure: booleanValue(browserOptions.screenshot_on_failure_default, "jev_browser_mcp.browser.screenshot_on_failure_default"),
|
|
247
|
+
traceOnFailure: booleanValue(browserOptions.trace_on_failure_default, "jev_browser_mcp.browser.trace_on_failure_default"),
|
|
248
|
+
captureConsoleErrors: booleanValue(browserOptions.capture_console_errors_default, "jev_browser_mcp.browser.capture_console_errors_default"),
|
|
249
|
+
captureNetworkErrors: booleanValue(browserOptions.capture_network_errors_default, "jev_browser_mcp.browser.capture_network_errors_default"),
|
|
250
|
+
blockTrackers: booleanValue(browserOptions.block_trackers_default, "jev_browser_mcp.browser.block_trackers_default"),
|
|
251
|
+
snapshotScope,
|
|
252
|
+
}),
|
|
253
|
+
trackerHostSuffixes: Object.freeze(trackerHostSuffixes),
|
|
254
|
+
blockedResourceTypes: Object.freeze(blockedResourceTypes),
|
|
246
255
|
}),
|
|
247
256
|
jev: Object.freeze({
|
|
248
257
|
providerUrl,
|
|
@@ -253,9 +262,10 @@ export function loadSettings({ env = process.env, configPath = CONFIG_PATH } = {
|
|
|
253
262
|
maxSnapshotChars: positiveNumber(document.jev.max_snapshot_chars, "jev.max_snapshot_chars", true),
|
|
254
263
|
maxActionCount: positiveNumber(document.jev.max_action_count, "jev.max_action_count", true),
|
|
255
264
|
maxActionDescriptionChars: positiveNumber(document.jev.max_action_description_chars, "jev.max_action_description_chars", true),
|
|
256
|
-
maxResponseBytes: positiveNumber(document.jev.max_response_bytes, "jev.max_response_bytes", true),
|
|
257
|
-
maxDiagnosticItems: positiveNumber(jevOptions.max_diagnostic_items, "jev_browser_mcp.jev.max_diagnostic_items", true),
|
|
258
|
-
maxDiagnosticChars: positiveNumber(jevOptions.max_diagnostic_chars, "jev_browser_mcp.jev.max_diagnostic_chars", true),
|
|
265
|
+
maxResponseBytes: positiveNumber(document.jev.max_response_bytes, "jev.max_response_bytes", true),
|
|
266
|
+
maxDiagnosticItems: positiveNumber(jevOptions.max_diagnostic_items, "jev_browser_mcp.jev.max_diagnostic_items", true),
|
|
267
|
+
maxDiagnosticChars: positiveNumber(jevOptions.max_diagnostic_chars, "jev_browser_mcp.jev.max_diagnostic_chars", true),
|
|
268
|
+
maxAccessibilityViolations: positiveNumber(jevOptions.max_accessibility_violations, "jev_browser_mcp.jev.max_accessibility_violations", true),
|
|
259
269
|
}),
|
|
260
270
|
});
|
|
261
271
|
}
|