@comecaramelos/dsh-chrome-mcp 0.0.1 → 1.0.0
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 +22 -78
- package/assets/dsh-chrome-mcp-social.png +0 -0
- package/assets/icon.svg +71 -0
- package/assets/prelaunch-windows-chrome.html +277 -0
- package/lib/client.js +1433 -568
- package/lib/client.js.map +7 -0
- package/lib/host/apply.d.ts +3 -0
- package/lib/host/apply.d.ts.map +1 -0
- package/lib/host/apply.js +31 -0
- package/lib/host/apply.js.map +1 -0
- package/lib/host/bridge.d.ts +65 -0
- package/lib/host/bridge.d.ts.map +1 -0
- package/lib/host/bridge.js +176 -0
- package/lib/host/bridge.js.map +1 -0
- package/lib/host/catalog.d.ts +31 -0
- package/lib/host/catalog.d.ts.map +1 -0
- package/lib/host/catalog.js +92 -0
- package/lib/host/catalog.js.map +1 -0
- package/lib/host/constants.d.ts +229 -0
- package/lib/host/constants.d.ts.map +1 -0
- package/lib/host/constants.js +242 -0
- package/lib/host/constants.js.map +1 -0
- package/lib/host/controller/bridge-run.d.ts +38 -0
- package/lib/host/controller/bridge-run.d.ts.map +1 -0
- package/lib/host/controller/bridge-run.js +69 -0
- package/lib/host/controller/bridge-run.js.map +1 -0
- package/lib/host/controller/captures.d.ts +22 -0
- package/lib/host/controller/captures.d.ts.map +1 -0
- package/lib/host/controller/captures.js +60 -0
- package/lib/host/controller/captures.js.map +1 -0
- package/lib/host/controller/commits.d.ts +4 -0
- package/lib/host/controller/commits.d.ts.map +1 -0
- package/lib/host/controller/commits.js +75 -0
- package/lib/host/controller/commits.js.map +1 -0
- package/lib/host/controller/controller.d.ts +40 -0
- package/lib/host/controller/controller.d.ts.map +1 -0
- package/lib/host/controller/controller.js +167 -0
- package/lib/host/controller/controller.js.map +1 -0
- package/lib/host/controller/index.d.ts +26 -0
- package/lib/host/controller/index.d.ts.map +1 -0
- package/lib/host/controller/index.js +25 -0
- package/lib/host/controller/index.js.map +1 -0
- package/lib/host/controller/notes.d.ts +26 -0
- package/lib/host/controller/notes.d.ts.map +1 -0
- package/lib/host/controller/notes.js +49 -0
- package/lib/host/controller/notes.js.map +1 -0
- package/lib/host/controller/persist.d.ts +9 -0
- package/lib/host/controller/persist.d.ts.map +1 -0
- package/lib/host/controller/persist.js +51 -0
- package/lib/host/controller/persist.js.map +1 -0
- package/lib/host/controller/runs.d.ts +56 -0
- package/lib/host/controller/runs.d.ts.map +1 -0
- package/lib/host/controller/runs.js +211 -0
- package/lib/host/controller/runs.js.map +1 -0
- package/lib/host/controller/state.d.ts +70 -0
- package/lib/host/controller/state.d.ts.map +1 -0
- package/lib/host/controller/state.js +2 -0
- package/lib/host/controller/state.js.map +1 -0
- package/lib/host/controller/windows-run.d.ts +9 -0
- package/lib/host/controller/windows-run.d.ts.map +1 -0
- package/lib/host/controller/windows-run.js +78 -0
- package/lib/host/controller/windows-run.js.map +1 -0
- package/lib/host/discovery/candidates.d.ts +37 -0
- package/lib/host/discovery/candidates.d.ts.map +1 -0
- package/lib/host/discovery/candidates.js +56 -0
- package/lib/host/discovery/candidates.js.map +1 -0
- package/lib/host/discovery/index.d.ts +18 -0
- package/lib/host/discovery/index.d.ts.map +1 -0
- package/lib/host/discovery/index.js +18 -0
- package/lib/host/discovery/index.js.map +1 -0
- package/lib/host/discovery/probe.d.ts +18 -0
- package/lib/host/discovery/probe.d.ts.map +1 -0
- package/lib/host/discovery/probe.js +97 -0
- package/lib/host/discovery/probe.js.map +1 -0
- package/lib/host/discovery/scan.d.ts +67 -0
- package/lib/host/discovery/scan.d.ts.map +1 -0
- package/lib/host/discovery/scan.js +169 -0
- package/lib/host/discovery/scan.js.map +1 -0
- package/lib/host/flags.d.ts +42 -0
- package/lib/host/flags.d.ts.map +1 -0
- package/lib/host/flags.js +118 -0
- package/lib/host/flags.js.map +1 -0
- package/lib/host/platform.d.ts +38 -0
- package/lib/host/platform.d.ts.map +1 -0
- package/lib/host/platform.js +64 -0
- package/lib/host/platform.js.map +1 -0
- package/lib/host/plugin-meta.d.ts +12 -0
- package/lib/host/plugin-meta.d.ts.map +1 -0
- package/lib/host/plugin-meta.js +12 -0
- package/lib/host/plugin-meta.js.map +1 -0
- package/lib/host/schema.d.ts +307 -0
- package/lib/host/schema.d.ts.map +1 -0
- package/lib/host/schema.js +171 -0
- package/lib/host/schema.js.map +1 -0
- package/lib/host/settings.d.ts +9 -0
- package/lib/host/settings.d.ts.map +1 -0
- package/lib/host/settings.js +70 -0
- package/lib/host/settings.js.map +1 -0
- package/lib/host/status.d.ts +28 -0
- package/lib/host/status.d.ts.map +1 -0
- package/lib/host/status.js +60 -0
- package/lib/host/status.js.map +1 -0
- package/lib/host/tool.d.ts +59 -0
- package/lib/host/tool.d.ts.map +1 -0
- package/lib/host/tool.js +51 -0
- package/lib/host/tool.js.map +1 -0
- package/lib/host/types/config.d.ts +47 -0
- package/lib/host/types/config.d.ts.map +1 -0
- package/lib/host/types/config.js +2 -0
- package/lib/host/types/config.js.map +1 -0
- package/lib/host/types/executable.d.ts +30 -0
- package/lib/host/types/executable.d.ts.map +1 -0
- package/lib/host/types/executable.js +9 -0
- package/lib/host/types/executable.js.map +1 -0
- package/lib/host/types/index.d.ts +23 -0
- package/lib/host/types/index.d.ts.map +1 -0
- package/lib/host/types/index.js +2 -0
- package/lib/host/types/index.js.map +1 -0
- package/lib/host/types/plugin.d.ts +38 -0
- package/lib/host/types/plugin.d.ts.map +1 -0
- package/lib/host/types/plugin.js +10 -0
- package/lib/host/types/plugin.js.map +1 -0
- package/lib/host/types/settings.d.ts +127 -0
- package/lib/host/types/settings.d.ts.map +1 -0
- package/lib/host/types/settings.js +2 -0
- package/lib/host/types/settings.js.map +1 -0
- package/lib/host/types/stderr.d.ts +53 -0
- package/lib/host/types/stderr.d.ts.map +1 -0
- package/lib/host/types/stderr.js +9 -0
- package/lib/host/types/stderr.js.map +1 -0
- package/lib/host/types/windows.d.ts +39 -0
- package/lib/host/types/windows.d.ts.map +1 -0
- package/lib/host/types/windows.js +9 -0
- package/lib/host/types/windows.js.map +1 -0
- package/lib/host/values.d.ts +89 -0
- package/lib/host/values.d.ts.map +1 -0
- package/lib/host/values.js +212 -0
- package/lib/host/values.js.map +1 -0
- package/lib/host/windows/connect-flags.d.ts +16 -0
- package/lib/host/windows/connect-flags.d.ts.map +1 -0
- package/lib/host/windows/connect-flags.js +67 -0
- package/lib/host/windows/connect-flags.js.map +1 -0
- package/lib/host/windows/index.d.ts +31 -0
- package/lib/host/windows/index.d.ts.map +1 -0
- package/lib/host/windows/index.js +30 -0
- package/lib/host/windows/index.js.map +1 -0
- package/lib/host/windows/landing.d.ts +47 -0
- package/lib/host/windows/landing.d.ts.map +1 -0
- package/lib/host/windows/landing.js +174 -0
- package/lib/host/windows/landing.js.map +1 -0
- package/lib/host/windows/link.d.ts +11 -0
- package/lib/host/windows/link.d.ts.map +1 -0
- package/lib/host/windows/link.js +52 -0
- package/lib/host/windows/link.js.map +1 -0
- package/lib/host/windows/paths.d.ts +43 -0
- package/lib/host/windows/paths.d.ts.map +1 -0
- package/lib/host/windows/paths.js +121 -0
- package/lib/host/windows/paths.js.map +1 -0
- package/lib/host/windows/run.d.ts +74 -0
- package/lib/host/windows/run.d.ts.map +1 -0
- package/lib/host/windows/run.js +210 -0
- package/lib/host/windows/run.js.map +1 -0
- package/lib/host/windows/spawn.d.ts +22 -0
- package/lib/host/windows/spawn.d.ts.map +1 -0
- package/lib/host/windows/spawn.js +73 -0
- package/lib/host/windows/spawn.js.map +1 -0
- package/lib/index.d.ts +86 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +72 -625
- package/lib/index.js.map +1 -0
- package/package.json +26 -4
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chrome discovery — the low-level `--version` probe and the on-disk/identity
|
|
3
|
+
* helpers it rides on.
|
|
4
|
+
*
|
|
5
|
+
* The one place discovery reaches outside the process: `chromePath --version`
|
|
6
|
+
* run through a scrubbed parent env under a bounded timeout, the rule that says
|
|
7
|
+
* whether a path is worth spawning at all (a directory, socket or fifo never
|
|
8
|
+
* reaches a probe — a Chrome-less host must run one scan that launches nothing),
|
|
9
|
+
* and the identity key that folds two spellings of the same binary into one
|
|
10
|
+
* answer. The scan that drives them lives in ./scan.ts.
|
|
11
|
+
*/
|
|
12
|
+
import { spawn } from "node:child_process";
|
|
13
|
+
import { accessSync, constants, realpathSync, statSync } from "node:fs";
|
|
14
|
+
import { scrubbedParentEnv } from "@deepseek-ai/dsh-subprocess";
|
|
15
|
+
import { CHECK_TIMEOUT_MS } from "../constants.js";
|
|
16
|
+
import { firstLine } from "../status.js";
|
|
17
|
+
/**
|
|
18
|
+
* Spawn one `chromePath --version` probe (scrubbed parent env, bounded
|
|
19
|
+
* timeout). Resolves the first stdout line (the version); ENOENT rejects with
|
|
20
|
+
* "Chrome executable not found: <path>" carrying code "ENOENT"; a non-zero
|
|
21
|
+
* exit rejects with the first non-empty stderr/stdout line.
|
|
22
|
+
*/
|
|
23
|
+
export function probeExecutable(target) {
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
let child;
|
|
26
|
+
try {
|
|
27
|
+
child = spawn(target, ["--version"], {
|
|
28
|
+
env: scrubbedParentEnv(),
|
|
29
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
30
|
+
timeout: CHECK_TIMEOUT_MS,
|
|
31
|
+
killSignal: "SIGKILL"
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
reject(new Error(`could not run "${target} --version": ${String(error)}`));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
let stdout = "";
|
|
39
|
+
let stderr = "";
|
|
40
|
+
child.stdout?.on("data", (chunk) => (stdout += chunk));
|
|
41
|
+
child.stderr?.on("data", (chunk) => (stderr += chunk));
|
|
42
|
+
child.on("error", (error) => {
|
|
43
|
+
const code = error && typeof error.code === "string" ? error.code : "";
|
|
44
|
+
if (code === "ENOENT") {
|
|
45
|
+
const missing = new Error(`Chrome executable not found: ${target}`);
|
|
46
|
+
Object.defineProperty(missing, "code", { value: "ENOENT", writable: true, enumerable: false, configurable: true });
|
|
47
|
+
reject(missing);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
reject(new Error(`could not run "${target} --version": ${String(error)}`));
|
|
51
|
+
});
|
|
52
|
+
child.on("close", (code) => {
|
|
53
|
+
if (code === null) {
|
|
54
|
+
reject(new Error(`"${target} --version" timed out after ${String(CHECK_TIMEOUT_MS)}ms`));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (code !== 0) {
|
|
58
|
+
const detail = firstLine(stderr) !== "" ? firstLine(stderr) : firstLine(stdout) !== "" ? firstLine(stdout) : `exit code ${String(code)}`;
|
|
59
|
+
reject(new Error(`"${target} --version" failed: ${detail}`));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
resolve(firstLine(stdout));
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/** True when a candidate path can be handed to the OS for a `--version` probe.
|
|
67
|
+
* A path that is absent (or not executable) never reaches the spawn: a
|
|
68
|
+
* Chrome-less host runs one scan without launching anything. Paths with no
|
|
69
|
+
* directory separator go straight to the spawn so the OS resolves them
|
|
70
|
+
* through `PATH`. */
|
|
71
|
+
export function presentOnDisk(candidate) {
|
|
72
|
+
if (!candidate.includes("/") && !candidate.includes("\\"))
|
|
73
|
+
return true;
|
|
74
|
+
try {
|
|
75
|
+
// A directory (or a socket, or a fifo) is not an executable, and
|
|
76
|
+
// spawning one to find out is a side effect we do not want.
|
|
77
|
+
if (!statSync(candidate).isFile())
|
|
78
|
+
return false;
|
|
79
|
+
accessSync(candidate, constants.X_OK);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Identity key used to fold two spellings of the same binary (`google-chrome`
|
|
87
|
+
* resolving onto `/usr/bin/google-chrome`) into one option. Falls back to the
|
|
88
|
+
* path itself when `realpath` cannot resolve it. */
|
|
89
|
+
export function identity(candidate) {
|
|
90
|
+
try {
|
|
91
|
+
return realpathSync(candidate);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return candidate;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probe.js","sourceRoot":"","sources":["../../../src/host/discovery/probe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ChromeExecutableStatus, ChromeMcpConfig } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* What one run probes: every candidate it has — the row-config candidate list,
|
|
4
|
+
* the paths the saved rows carry, and the current selection (see
|
|
5
|
+
* {@link chromeExecutableCandidates}) — probed in that order.
|
|
6
|
+
*
|
|
7
|
+
* A candidate that runs answers with its `--version` line; one that is present
|
|
8
|
+
* but not runnable (bad binary, a probe that timed out) keeps its place in the
|
|
9
|
+
* list carrying the failure, so a broken pin stays visible instead of vanishing
|
|
10
|
+
* into a red dot.
|
|
11
|
+
*
|
|
12
|
+
* - absent / not executable → dropped without a spawn,
|
|
13
|
+
* - `blockedForPlatform` answers non-empty → **no spawn**: the candidate keeps
|
|
14
|
+
* its place carrying that reason (the one case is a Windows `chrome.exe` on a
|
|
15
|
+
* WSL host, whose probe would start a browser instance it can never drive —
|
|
16
|
+
* see {@link WSL_WINDOWS_LAUNCH_ERROR}),
|
|
17
|
+
* - two spellings of the same binary collapse into the first one seen.
|
|
18
|
+
*
|
|
19
|
+
* An empty candidate list resolves `[]` (nothing probed: unknown platform, or a
|
|
20
|
+
* host patched down to nothing).
|
|
21
|
+
*
|
|
22
|
+
* @param candidates - candidate executable paths.
|
|
23
|
+
* @param blockedForPlatform - answers a reason for a candidate this host must
|
|
24
|
+
* never exec, `""` for one it may probe.
|
|
25
|
+
*/
|
|
26
|
+
export declare function scanChromeExecutables(candidates: string[], blockedForPlatform?: (candidate: string) => string): Promise<ChromeExecutableStatus[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Discover usable Google Chrome executables when nothing is fixed: probe every
|
|
29
|
+
* candidate and report the first runnable one. Kept for its `Promise<string>`
|
|
30
|
+
* contract (`src/index.ts` re-export, tests, diagnostics).
|
|
31
|
+
* @param candidatePaths - candidate executable paths (default: platform list).
|
|
32
|
+
* @param blockedForPlatform - answers a reason for a candidate this host must
|
|
33
|
+
* never exec, `""` for one it may probe.
|
|
34
|
+
* @returns the discovered executable version line.
|
|
35
|
+
*/
|
|
36
|
+
export declare function discoverChrome(candidatePaths: string[], blockedForPlatform?: (candidate: string) => string): Promise<string>;
|
|
37
|
+
/**
|
|
38
|
+
* One check run — the public "did we find a runnable Chrome?" question:
|
|
39
|
+
*
|
|
40
|
+
* - `chromePath` non-empty → probe that executable (ENOENT → "Chrome
|
|
41
|
+
* executable not found: <path>"; non-zero → first stderr/stdout line;
|
|
42
|
+
* success → the version line).
|
|
43
|
+
* - `chromePath` empty → run the scan over the candidate list (row config
|
|
44
|
+
* `chromePaths`, default {@link defaultChromePaths}) and report the first
|
|
45
|
+
* runnable entry. Nothing usable → the known executable-missing error;
|
|
46
|
+
* only-present-but-broken entries → that entry's failure.
|
|
47
|
+
* - the extra flags declare a connect mode (`--browserUrl` / `--wsEndpoint`) →
|
|
48
|
+
* resolve "": there is no local executable to check.
|
|
49
|
+
* - `blockedForPlatform` answers non-empty for what is selected → resolve "" with
|
|
50
|
+
* **no spawn**. A Windows `chrome.exe` on a WSL host is the case: its
|
|
51
|
+
* `--version` probe answers (which is why the selection looks healthy) but
|
|
52
|
+
* answering means attaching to the Windows browser session, and that *starts*
|
|
53
|
+
* a browser instance no tool call could drive
|
|
54
|
+
* ({@link WSL_WINDOWS_LAUNCH_ERROR}).
|
|
55
|
+
*
|
|
56
|
+
* A run that probes **nothing** (no candidates, a connect mode, or a blocked
|
|
57
|
+
* path) resolves "" — callers must treat that as "no evidence", never as health.
|
|
58
|
+
*
|
|
59
|
+
* @param entry - validated {@link ChromeMcpConfig}.
|
|
60
|
+
* @param extraFlags - the flags list the bridge currently launches with; only
|
|
61
|
+
* inspected for connect-mode options.
|
|
62
|
+
* @param blockedForPlatform - answers a reason for a path this host must never
|
|
63
|
+
* exec, `""` for one it may probe.
|
|
64
|
+
* @returns the executable version line, or "" when nothing is probed.
|
|
65
|
+
*/
|
|
66
|
+
export declare function checkChrome(entry: ChromeMcpConfig, extraFlags?: string[], blockedForPlatform?: (candidate: string) => string): Promise<string>;
|
|
67
|
+
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/host/discovery/scan.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAKjF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,qBAAqB,CACvC,UAAU,EAAE,MAAM,EAAE,EACpB,kBAAkB,GAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAiB,GAC7D,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAyCnC;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAChC,cAAc,EAAE,MAAM,EAAE,EACxB,kBAAkB,GAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAiB,GAC7D,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,WAAW,CACvB,KAAK,EAAE,eAAe,EACtB,UAAU,CAAC,EAAE,MAAM,EAAE,EACrB,kBAAkB,GAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAiB,GAC7D,OAAO,CAAC,MAAM,CAAC,CAYjB"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chrome discovery — the scan and the check run that tie it together.
|
|
3
|
+
*
|
|
4
|
+
* What one executable run does: probe every candidate it has (the row-config
|
|
5
|
+
* list, the saved rows' ids, the selection), publish the per-path answer, and
|
|
6
|
+
* report the first runnable one. The candidate ordering lives in
|
|
7
|
+
* ./candidates.ts; the `--version` probe + presence + identity helpers in
|
|
8
|
+
* ./probe.ts.
|
|
9
|
+
*
|
|
10
|
+
* Upstream (`chrome-devtools-mcp`, via puppeteer) starts the browser only
|
|
11
|
+
* LAZILY, on the first tool call — so without a probe of our own, a
|
|
12
|
+
* Chrome-less host would show nothing until somebody called a tool. The scan
|
|
13
|
+
* therefore probes eagerly: there is no "auto" mode, the scan lists what exists,
|
|
14
|
+
* the card picks one of them, and what is picked stays picked.
|
|
15
|
+
*
|
|
16
|
+
* WSL NOTE: the executable must be a Linux binary. Launching the Windows
|
|
17
|
+
* chrome.exe through the WSL interop layer fails: chrome-devtools-mcp connects
|
|
18
|
+
* with `pipe: true` (inherited fd 3/4), and Windows-side processes cannot
|
|
19
|
+
* receive those pipes from WSL; the WebSocket fallback hard-codes 127.0.0.1 in
|
|
20
|
+
* the DevToolsActivePort file, unreachable across the WSL2 NAT bridge. Verified
|
|
21
|
+
* empirically 2025-09-19 (.probe/); do not "fix" discovery by pointing candidates
|
|
22
|
+
* or chromePath at a /mnt/c executable.
|
|
23
|
+
*/
|
|
24
|
+
import { carriesConnectionMode } from "../flags.js";
|
|
25
|
+
import { firstLine } from "../status.js";
|
|
26
|
+
import { defaultChromePaths } from "./candidates.js";
|
|
27
|
+
import { identity, presentOnDisk, probeExecutable } from "./probe.js";
|
|
28
|
+
/**
|
|
29
|
+
* What one run probes: every candidate it has — the row-config candidate list,
|
|
30
|
+
* the paths the saved rows carry, and the current selection (see
|
|
31
|
+
* {@link chromeExecutableCandidates}) — probed in that order.
|
|
32
|
+
*
|
|
33
|
+
* A candidate that runs answers with its `--version` line; one that is present
|
|
34
|
+
* but not runnable (bad binary, a probe that timed out) keeps its place in the
|
|
35
|
+
* list carrying the failure, so a broken pin stays visible instead of vanishing
|
|
36
|
+
* into a red dot.
|
|
37
|
+
*
|
|
38
|
+
* - absent / not executable → dropped without a spawn,
|
|
39
|
+
* - `blockedForPlatform` answers non-empty → **no spawn**: the candidate keeps
|
|
40
|
+
* its place carrying that reason (the one case is a Windows `chrome.exe` on a
|
|
41
|
+
* WSL host, whose probe would start a browser instance it can never drive —
|
|
42
|
+
* see {@link WSL_WINDOWS_LAUNCH_ERROR}),
|
|
43
|
+
* - two spellings of the same binary collapse into the first one seen.
|
|
44
|
+
*
|
|
45
|
+
* An empty candidate list resolves `[]` (nothing probed: unknown platform, or a
|
|
46
|
+
* host patched down to nothing).
|
|
47
|
+
*
|
|
48
|
+
* @param candidates - candidate executable paths.
|
|
49
|
+
* @param blockedForPlatform - answers a reason for a candidate this host must
|
|
50
|
+
* never exec, `""` for one it may probe.
|
|
51
|
+
*/
|
|
52
|
+
export async function scanChromeExecutables(candidates, blockedForPlatform = () => "") {
|
|
53
|
+
const list = Array.isArray(candidates) ? candidates : [];
|
|
54
|
+
const statuses = [];
|
|
55
|
+
const seen = new Set();
|
|
56
|
+
for (const candidate of list) {
|
|
57
|
+
const path = String(candidate ?? "").trim();
|
|
58
|
+
if (path === "")
|
|
59
|
+
continue;
|
|
60
|
+
const blocked = blockedForPlatform(path);
|
|
61
|
+
if (blocked !== "") {
|
|
62
|
+
// Never spawned: what a blocked candidate would do is start a
|
|
63
|
+
// browser this host could not drive. It stays on the list so the
|
|
64
|
+
// card can name it instead of dropping it into a red dot.
|
|
65
|
+
const key = `blocked\u0000${identity(path)}`;
|
|
66
|
+
if (seen.has(key))
|
|
67
|
+
continue;
|
|
68
|
+
seen.add(key);
|
|
69
|
+
statuses.push({ path, version: "", error: blocked });
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (!presentOnDisk(path))
|
|
73
|
+
continue;
|
|
74
|
+
try {
|
|
75
|
+
const version = await probeExecutable(path);
|
|
76
|
+
const key = `${identity(path)}\u0000${version}`;
|
|
77
|
+
if (seen.has(key))
|
|
78
|
+
continue;
|
|
79
|
+
seen.add(key);
|
|
80
|
+
statuses.push({ path, version, error: "" });
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
const code = (error instanceof Error && typeof error.code === "string")
|
|
84
|
+
? error.code
|
|
85
|
+
: "";
|
|
86
|
+
if (code === "ENOENT")
|
|
87
|
+
continue;
|
|
88
|
+
const key = identity(path);
|
|
89
|
+
if (seen.has(key))
|
|
90
|
+
continue;
|
|
91
|
+
seen.add(key);
|
|
92
|
+
statuses.push({
|
|
93
|
+
path,
|
|
94
|
+
version: "",
|
|
95
|
+
error: firstLine(error instanceof Error ? error.message : String(error))
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return statuses;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Discover usable Google Chrome executables when nothing is fixed: probe every
|
|
103
|
+
* candidate and report the first runnable one. Kept for its `Promise<string>`
|
|
104
|
+
* contract (`src/index.ts` re-export, tests, diagnostics).
|
|
105
|
+
* @param candidatePaths - candidate executable paths (default: platform list).
|
|
106
|
+
* @param blockedForPlatform - answers a reason for a candidate this host must
|
|
107
|
+
* never exec, `""` for one it may probe.
|
|
108
|
+
* @returns the discovered executable version line.
|
|
109
|
+
*/
|
|
110
|
+
export async function discoverChrome(candidatePaths, blockedForPlatform = () => "") {
|
|
111
|
+
const candidates = (Array.isArray(candidatePaths) ? candidatePaths : defaultChromePaths())
|
|
112
|
+
.map((candidate) => String(candidate ?? "").trim())
|
|
113
|
+
.filter((candidate) => candidate !== "");
|
|
114
|
+
if (candidates.length === 0)
|
|
115
|
+
return "";
|
|
116
|
+
const found = await scanChromeExecutables(candidates, blockedForPlatform);
|
|
117
|
+
for (const status of found) {
|
|
118
|
+
if (status.version !== "" && status.error === "")
|
|
119
|
+
return status.version;
|
|
120
|
+
}
|
|
121
|
+
const broken = found.find((status) => status.error !== "");
|
|
122
|
+
if (broken !== void 0)
|
|
123
|
+
throw new Error(broken.error);
|
|
124
|
+
throw new Error(`Chrome executable not found: no executable detected (checked: ${candidates.join(", ")})`);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* One check run — the public "did we find a runnable Chrome?" question:
|
|
128
|
+
*
|
|
129
|
+
* - `chromePath` non-empty → probe that executable (ENOENT → "Chrome
|
|
130
|
+
* executable not found: <path>"; non-zero → first stderr/stdout line;
|
|
131
|
+
* success → the version line).
|
|
132
|
+
* - `chromePath` empty → run the scan over the candidate list (row config
|
|
133
|
+
* `chromePaths`, default {@link defaultChromePaths}) and report the first
|
|
134
|
+
* runnable entry. Nothing usable → the known executable-missing error;
|
|
135
|
+
* only-present-but-broken entries → that entry's failure.
|
|
136
|
+
* - the extra flags declare a connect mode (`--browserUrl` / `--wsEndpoint`) →
|
|
137
|
+
* resolve "": there is no local executable to check.
|
|
138
|
+
* - `blockedForPlatform` answers non-empty for what is selected → resolve "" with
|
|
139
|
+
* **no spawn**. A Windows `chrome.exe` on a WSL host is the case: its
|
|
140
|
+
* `--version` probe answers (which is why the selection looks healthy) but
|
|
141
|
+
* answering means attaching to the Windows browser session, and that *starts*
|
|
142
|
+
* a browser instance no tool call could drive
|
|
143
|
+
* ({@link WSL_WINDOWS_LAUNCH_ERROR}).
|
|
144
|
+
*
|
|
145
|
+
* A run that probes **nothing** (no candidates, a connect mode, or a blocked
|
|
146
|
+
* path) resolves "" — callers must treat that as "no evidence", never as health.
|
|
147
|
+
*
|
|
148
|
+
* @param entry - validated {@link ChromeMcpConfig}.
|
|
149
|
+
* @param extraFlags - the flags list the bridge currently launches with; only
|
|
150
|
+
* inspected for connect-mode options.
|
|
151
|
+
* @param blockedForPlatform - answers a reason for a path this host must never
|
|
152
|
+
* exec, `""` for one it may probe.
|
|
153
|
+
* @returns the executable version line, or "" when nothing is probed.
|
|
154
|
+
*/
|
|
155
|
+
export function checkChrome(entry, extraFlags, blockedForPlatform = () => "") {
|
|
156
|
+
const target = typeof entry.chromePath === "string" ? entry.chromePath.trim() : "";
|
|
157
|
+
if (target !== "")
|
|
158
|
+
return blockedForPlatform(target) !== "" ? Promise.resolve("") : probeExecutable(target);
|
|
159
|
+
const flags = Array.isArray(extraFlags)
|
|
160
|
+
? extraFlags
|
|
161
|
+
: Array.isArray(entry.extraFlags)
|
|
162
|
+
? entry.extraFlags
|
|
163
|
+
: [];
|
|
164
|
+
if (flags.some((flag) => typeof flag === "string" && carriesConnectionMode(flag))) {
|
|
165
|
+
return Promise.resolve("");
|
|
166
|
+
}
|
|
167
|
+
return discoverChrome(entry.chromePaths, blockedForPlatform);
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/host/discovery/scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate a user-authored extraFlags list: a plain array of flag strings
|
|
3
|
+
* carrying no control characters (argv is execve'd without a shell), and no
|
|
4
|
+
* executable-path flag — the executable is picked in the card's selector, so
|
|
5
|
+
* letting a flag pin one would put a second source of truth over the bridge
|
|
6
|
+
* argv. Throws with the offending entry so the settings layer can surface it.
|
|
7
|
+
* @param value - candidate flags array.
|
|
8
|
+
* @returns true when valid.
|
|
9
|
+
*/
|
|
10
|
+
export declare function validateExtraFlags(value: unknown): true;
|
|
11
|
+
/** True when a flag selects the Chrome executable (upstream flags:
|
|
12
|
+
* `--executablePath` / `--executable-path` / `-e`, with or without `=`).
|
|
13
|
+
* No longer an accepted user flag (see {@link validateExtraFlags}): it stays
|
|
14
|
+
* here for the row-config fold ({@link extractExecutablePathFlag}) and the
|
|
15
|
+
* argv guard. */
|
|
16
|
+
export declare function carriesExecutablePath(flag: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Read the path a legacy `--executablePath` carries in the **row-config** flags
|
|
19
|
+
* list: the `=` spelling and the separated spelling both count, first entry
|
|
20
|
+
* wins, "" when nothing pins a path.
|
|
21
|
+
*
|
|
22
|
+
* The card's picker owns the executable now, so a row-config pin is not
|
|
23
|
+
* honored as a flag: it becomes the row-config source of the selection and gets
|
|
24
|
+
* stripped out of argv (see {@link stripExecutablePathFlags}).
|
|
25
|
+
*/
|
|
26
|
+
export declare function extractExecutablePathFlag(flags: unknown): string;
|
|
27
|
+
/** Drop every entry that pins an executable from a flags list — paired with
|
|
28
|
+
* {@link extractExecutablePathFlag} so a legacy profile keeps its path as a
|
|
29
|
+
* selection source instead of reaching argv as a second source of truth.
|
|
30
|
+
* A `--flag <path>` spelling consumes the following entry; a flag-looking next
|
|
31
|
+
* entry keeps it (nothing was meant as the value). */
|
|
32
|
+
export declare function stripExecutablePathFlags(flags: unknown): string[];
|
|
33
|
+
/** True when one extraFlag declares a connect mode (no local executable). */
|
|
34
|
+
export declare function carriesConnectionMode(flag: string): boolean;
|
|
35
|
+
/** True when any entry of a flags list declares connect mode — the only thing
|
|
36
|
+
* that now spares the bridge from an executable probe. A flag that pins an
|
|
37
|
+
* executable is rejected on the way in instead (see
|
|
38
|
+
* {@link validateExtraFlags}). */
|
|
39
|
+
export declare function flagsSkipCheck(flags: unknown): boolean;
|
|
40
|
+
/** True when two flags lists are element-wise equal (flags are arrays). */
|
|
41
|
+
export declare function sameFlags(a: unknown, b: unknown): boolean;
|
|
42
|
+
//# sourceMappingURL=flags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flags.d.ts","sourceRoot":"","sources":["../../src/host/flags.ts"],"names":[],"mappings":"AAoBA;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAkBvD;AAED;;;;iBAIiB;AACjB,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAWhE;AAED;;;;sDAIsD;AACtD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAejE;AAED,6EAA6E;AAC7E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED;;;kCAGkC;AAClC,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEtD;AAED,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAGzD"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extra-flags helpers shared by the bridge argv builder, the executable scan
|
|
3
|
+
* and the settings validation hook.
|
|
4
|
+
*
|
|
5
|
+
* Flags are execve'd as argv entries — never through a shell — so validation
|
|
6
|
+
* rejects control characters only, and the executable pin / connect-mode
|
|
7
|
+
* options are matched against their upstream spellings (`--executablePath`,
|
|
8
|
+
* `--executable-path`, `-e`, `--browserUrl`, `--wsEndpoint`).
|
|
9
|
+
*
|
|
10
|
+
* One rule has since hardened: pinning the executable by flag is a second
|
|
11
|
+
* source of truth for the same lever the executable picker owns, so a
|
|
12
|
+
* user-authored list may not carry it (`validateExtraFlags` rejects it), and
|
|
13
|
+
* the row config's copy gets folded into `chromePath` instead of reaching argv
|
|
14
|
+
* as a second opinion.
|
|
15
|
+
*/
|
|
16
|
+
import { CONTROL_PATTERN } from "./constants.js";
|
|
17
|
+
/** One executable-path flag, upstream spellings, with or without `=`. */
|
|
18
|
+
const EXECUTABLE_PATH_FLAG = /^(?:--executablePath|--executable-path|-e)(?:=|(?=\s)|$)/iu;
|
|
19
|
+
/**
|
|
20
|
+
* Validate a user-authored extraFlags list: a plain array of flag strings
|
|
21
|
+
* carrying no control characters (argv is execve'd without a shell), and no
|
|
22
|
+
* executable-path flag — the executable is picked in the card's selector, so
|
|
23
|
+
* letting a flag pin one would put a second source of truth over the bridge
|
|
24
|
+
* argv. Throws with the offending entry so the settings layer can surface it.
|
|
25
|
+
* @param value - candidate flags array.
|
|
26
|
+
* @returns true when valid.
|
|
27
|
+
*/
|
|
28
|
+
export function validateExtraFlags(value) {
|
|
29
|
+
if (!Array.isArray(value)) {
|
|
30
|
+
throw new Error("extraFlags must be an array of strings");
|
|
31
|
+
}
|
|
32
|
+
for (const flag of value) {
|
|
33
|
+
if (typeof flag !== "string" || flag === "") {
|
|
34
|
+
throw new Error("extraFlags entries must be non-empty strings");
|
|
35
|
+
}
|
|
36
|
+
if (CONTROL_PATTERN.test(flag)) {
|
|
37
|
+
throw new Error(`extraFlags entry "${flag}" contains control characters`);
|
|
38
|
+
}
|
|
39
|
+
if (carriesExecutablePath(flag)) {
|
|
40
|
+
throw new Error(`extraFlags entry "${flag}" selects the Chrome executable — pick it in the Chrome executable picker instead`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
/** True when a flag selects the Chrome executable (upstream flags:
|
|
46
|
+
* `--executablePath` / `--executable-path` / `-e`, with or without `=`).
|
|
47
|
+
* No longer an accepted user flag (see {@link validateExtraFlags}): it stays
|
|
48
|
+
* here for the row-config fold ({@link extractExecutablePathFlag}) and the
|
|
49
|
+
* argv guard. */
|
|
50
|
+
export function carriesExecutablePath(flag) {
|
|
51
|
+
return typeof flag === "string" && EXECUTABLE_PATH_FLAG.test(flag);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Read the path a legacy `--executablePath` carries in the **row-config** flags
|
|
55
|
+
* list: the `=` spelling and the separated spelling both count, first entry
|
|
56
|
+
* wins, "" when nothing pins a path.
|
|
57
|
+
*
|
|
58
|
+
* The card's picker owns the executable now, so a row-config pin is not
|
|
59
|
+
* honored as a flag: it becomes the row-config source of the selection and gets
|
|
60
|
+
* stripped out of argv (see {@link stripExecutablePathFlags}).
|
|
61
|
+
*/
|
|
62
|
+
export function extractExecutablePathFlag(flags) {
|
|
63
|
+
if (!Array.isArray(flags))
|
|
64
|
+
return "";
|
|
65
|
+
for (let index = 0; index < flags.length; index++) {
|
|
66
|
+
const flag = flags[index];
|
|
67
|
+
if (typeof flag !== "string" || !carriesExecutablePath(flag))
|
|
68
|
+
continue;
|
|
69
|
+
const eq = flag.indexOf("=");
|
|
70
|
+
if (eq !== -1)
|
|
71
|
+
return flag.slice(eq + 1).trim();
|
|
72
|
+
const next = flags[index + 1];
|
|
73
|
+
return typeof next === "string" && next.trim() !== "" ? next.trim() : "";
|
|
74
|
+
}
|
|
75
|
+
return "";
|
|
76
|
+
}
|
|
77
|
+
/** Drop every entry that pins an executable from a flags list — paired with
|
|
78
|
+
* {@link extractExecutablePathFlag} so a legacy profile keeps its path as a
|
|
79
|
+
* selection source instead of reaching argv as a second source of truth.
|
|
80
|
+
* A `--flag <path>` spelling consumes the following entry; a flag-looking next
|
|
81
|
+
* entry keeps it (nothing was meant as the value). */
|
|
82
|
+
export function stripExecutablePathFlags(flags) {
|
|
83
|
+
if (!Array.isArray(flags))
|
|
84
|
+
return [];
|
|
85
|
+
const stripped = [];
|
|
86
|
+
let awaitingValue = false;
|
|
87
|
+
for (const flag of flags) {
|
|
88
|
+
if (typeof flag !== "string")
|
|
89
|
+
continue;
|
|
90
|
+
if (carriesExecutablePath(flag)) {
|
|
91
|
+
awaitingValue = !flag.includes("=");
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (awaitingValue && !flag.startsWith("-"))
|
|
95
|
+
continue;
|
|
96
|
+
awaitingValue = false;
|
|
97
|
+
stripped.push(flag);
|
|
98
|
+
}
|
|
99
|
+
return stripped;
|
|
100
|
+
}
|
|
101
|
+
/** True when one extraFlag declares a connect mode (no local executable). */
|
|
102
|
+
export function carriesConnectionMode(flag) {
|
|
103
|
+
return /^--(?:browserUrl|wsEndpoint)(?:=|(?=\s)|$)/iu.test(flag);
|
|
104
|
+
}
|
|
105
|
+
/** True when any entry of a flags list declares connect mode — the only thing
|
|
106
|
+
* that now spares the bridge from an executable probe. A flag that pins an
|
|
107
|
+
* executable is rejected on the way in instead (see
|
|
108
|
+
* {@link validateExtraFlags}). */
|
|
109
|
+
export function flagsSkipCheck(flags) {
|
|
110
|
+
return Array.isArray(flags) && flags.some((flag) => typeof flag === "string" && carriesConnectionMode(flag));
|
|
111
|
+
}
|
|
112
|
+
/** True when two flags lists are element-wise equal (flags are arrays). */
|
|
113
|
+
export function sameFlags(a, b) {
|
|
114
|
+
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)
|
|
115
|
+
return false;
|
|
116
|
+
return a.every((flag, index) => flag === b[index]);
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=flags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../../src/host/flags.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Everything {@link isWindowsSubsystemForLinux} consults; each field defaults
|
|
2
|
+
* to what the running process actually is. */
|
|
3
|
+
export type PlatformProbe = {
|
|
4
|
+
/** Defaults to `process.platform`. */
|
|
5
|
+
platform?: NodeJS.Platform;
|
|
6
|
+
/** Variable lookup; defaults to `process.env`. When a source is supplied its
|
|
7
|
+
* silence is the answer — the marker file is then not consulted, so a host
|
|
8
|
+
* that resolves its launch environment gets one deterministic answer
|
|
9
|
+
* instead of one that depends on the machine it booted on. */
|
|
10
|
+
env?: (name: string) => unknown;
|
|
11
|
+
/** File-presence lookup used only when `env` is not supplied (a bare call
|
|
12
|
+
* with no host to resolve against); defaults to the interop marker. */
|
|
13
|
+
exists?: (path: string) => boolean;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* True when `path` names a Windows binary — one that lives on the interop mount
|
|
17
|
+
* (`/mnt/<drive>/…`), in a Windows spelling (`\\host\…`, `C:\…`), or simply
|
|
18
|
+
* carries the PE suffix. A Linux path is never Windows-side, and a candidate
|
|
19
|
+
* list built from {@link DEFAULT_CHROME_PATHS} never matches.
|
|
20
|
+
* @param path - one executable path as selected.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isWindowsExecutablePath(path: unknown): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* True when the current process runs inside Windows Subsystem for Linux: a
|
|
25
|
+
* Linux kernel plus the WSL markers. A non-Linux platform (a plain Windows
|
|
26
|
+
* host) is never "under WSL", whatever its environment says.
|
|
27
|
+
* @param probe - what to consult (defaults to this process).
|
|
28
|
+
*/
|
|
29
|
+
export declare function isWindowsSubsystemForLinux(probe?: PlatformProbe): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The interop trap the card warns about: we are under WSL **and** what is
|
|
32
|
+
* selected is a Windows executable. Both halves are required — a Linux binary
|
|
33
|
+
* selected on a Windows host is simply nothing to say.
|
|
34
|
+
* @param path - the effective executable path.
|
|
35
|
+
* @param probe - what to consult for the environment (defaults to this process).
|
|
36
|
+
*/
|
|
37
|
+
export declare function isWindowsExecutableUnderWsl(path: unknown, probe?: PlatformProbe): boolean;
|
|
38
|
+
//# sourceMappingURL=platform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/host/platform.ts"],"names":[],"mappings":"AAsBA;8CAC8C;AAC9C,MAAM,MAAM,aAAa,GAAG;IACxB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B;;;kEAG8D;IAC9D,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC;2EACuE;IACvE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACtC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAK9D;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,GAAE,aAAkB,GAAG,OAAO,CAU7E;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,GAAE,aAAkB,GAAG,OAAO,CAE7F"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host half — where the plugin is running: is this Linux host a Windows
|
|
3
|
+
* Subsystem for Linux instance, and does one executable path name a Windows
|
|
4
|
+
* binary rather than a Linux one.
|
|
5
|
+
*
|
|
6
|
+
* The two answers only ever combine into one warning. Launching a Windows
|
|
7
|
+
* `chrome.exe` from WSL cannot work (`.probe/`, AGENTS.md): the debug pipes
|
|
8
|
+
* `chrome-devtools-mcp` opens do not survive the interop boundary, and the
|
|
9
|
+
* debugging port it reads from `DevToolsActivePort` stays bound to the Windows
|
|
10
|
+
* loopback, unreachable across the WSL2 NAT bridge. It even *seems* to work: the
|
|
11
|
+
* `--version` probe answers successfully, so a broken selection hides behind a
|
|
12
|
+
* healthy pill until the first tool call. That is why the pair is surfaced on
|
|
13
|
+
* the card as its own notice rather than through the error dot: nothing is
|
|
14
|
+
* failing yet, the required configuration is simply different.
|
|
15
|
+
*
|
|
16
|
+
* Both probes stay pure and injectable (`platform`, `env`, `exists`) so the
|
|
17
|
+
* tests never depend on the machine they run on.
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync } from "node:fs";
|
|
20
|
+
import { WINDOWS_EXE_PATTERN, WINDOWS_PATH_PATTERN, WSL_ENV_VARS, WSL_INTEROP_MARKER } from "./constants.js";
|
|
21
|
+
/**
|
|
22
|
+
* True when `path` names a Windows binary — one that lives on the interop mount
|
|
23
|
+
* (`/mnt/<drive>/…`), in a Windows spelling (`\\host\…`, `C:\…`), or simply
|
|
24
|
+
* carries the PE suffix. A Linux path is never Windows-side, and a candidate
|
|
25
|
+
* list built from {@link DEFAULT_CHROME_PATHS} never matches.
|
|
26
|
+
* @param path - one executable path as selected.
|
|
27
|
+
*/
|
|
28
|
+
export function isWindowsExecutablePath(path) {
|
|
29
|
+
if (typeof path !== "string")
|
|
30
|
+
return false;
|
|
31
|
+
const candidate = path.trim();
|
|
32
|
+
if (candidate === "")
|
|
33
|
+
return false;
|
|
34
|
+
return WINDOWS_PATH_PATTERN.test(candidate) || WINDOWS_EXE_PATTERN.test(candidate);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* True when the current process runs inside Windows Subsystem for Linux: a
|
|
38
|
+
* Linux kernel plus the WSL markers. A non-Linux platform (a plain Windows
|
|
39
|
+
* host) is never "under WSL", whatever its environment says.
|
|
40
|
+
* @param probe - what to consult (defaults to this process).
|
|
41
|
+
*/
|
|
42
|
+
export function isWindowsSubsystemForLinux(probe = {}) {
|
|
43
|
+
const platform = probe.platform ?? process.platform;
|
|
44
|
+
if (platform !== "linux")
|
|
45
|
+
return false;
|
|
46
|
+
if (probe.env !== void 0) {
|
|
47
|
+
return WSL_ENV_VARS.some((name) => {
|
|
48
|
+
const value = probe.env(name);
|
|
49
|
+
return typeof value === "string" && value.trim() !== "";
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return (probe.exists ?? ((candidate) => existsSync(candidate)))(WSL_INTEROP_MARKER);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The interop trap the card warns about: we are under WSL **and** what is
|
|
56
|
+
* selected is a Windows executable. Both halves are required — a Linux binary
|
|
57
|
+
* selected on a Windows host is simply nothing to say.
|
|
58
|
+
* @param path - the effective executable path.
|
|
59
|
+
* @param probe - what to consult for the environment (defaults to this process).
|
|
60
|
+
*/
|
|
61
|
+
export function isWindowsExecutableUnderWsl(path, probe = {}) {
|
|
62
|
+
return isWindowsSubsystemForLinux(probe) && isWindowsExecutablePath(path);
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/host/platform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAiB7G;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAa;IACjD,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,SAAS,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IACnC,OAAO,oBAAoB,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AACvF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,QAAuB,EAAE;IAChE,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IACpD,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,GAAI,CAAC,IAAI,CAAC,CAAC;YAC/B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;QAC5D,CAAC,CAAC,CAAC;IACP,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,SAAiB,EAAE,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;AAChG,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CAAC,IAAa,EAAE,QAAuB,EAAE;IAChF,OAAO,0BAA0B,CAAC,KAAK,CAAC,IAAI,uBAAuB,CAAC,IAAI,CAAC,CAAC;AAC9E,CAAC"}
|