@comecaramelos/dsh-chrome-mcp 0.0.1 → 2.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.
Files changed (214) hide show
  1. package/README.md +44 -95
  2. package/assets/dsh-chrome-mcp-social.png +0 -0
  3. package/assets/icon.svg +71 -0
  4. package/assets/prelaunch-windows-chrome.html +277 -0
  5. package/lib/client.js +3005 -568
  6. package/lib/client.js.map +7 -0
  7. package/lib/host/apply.d.ts +40 -0
  8. package/lib/host/apply.d.ts.map +1 -0
  9. package/lib/host/apply.js +57 -0
  10. package/lib/host/apply.js.map +1 -0
  11. package/lib/host/bridge.d.ts +74 -0
  12. package/lib/host/bridge.d.ts.map +1 -0
  13. package/lib/host/bridge.js +168 -0
  14. package/lib/host/bridge.js.map +1 -0
  15. package/lib/host/catalog.d.ts +31 -0
  16. package/lib/host/catalog.d.ts.map +1 -0
  17. package/lib/host/catalog.js +92 -0
  18. package/lib/host/catalog.js.map +1 -0
  19. package/lib/host/commands/chrome-path.d.ts +4 -0
  20. package/lib/host/commands/chrome-path.d.ts.map +1 -0
  21. package/lib/host/commands/chrome-path.js +65 -0
  22. package/lib/host/commands/chrome-path.js.map +1 -0
  23. package/lib/host/commands/chrome-refresh.d.ts +17 -0
  24. package/lib/host/commands/chrome-refresh.d.ts.map +1 -0
  25. package/lib/host/commands/chrome-refresh.js +37 -0
  26. package/lib/host/commands/chrome-refresh.js.map +1 -0
  27. package/lib/host/commands/index.d.ts +26 -0
  28. package/lib/host/commands/index.d.ts.map +1 -0
  29. package/lib/host/commands/index.js +41 -0
  30. package/lib/host/commands/index.js.map +1 -0
  31. package/lib/host/constants.d.ts +306 -0
  32. package/lib/host/constants.d.ts.map +1 -0
  33. package/lib/host/constants.js +319 -0
  34. package/lib/host/constants.js.map +1 -0
  35. package/lib/host/controller/_trace.d.ts +3 -0
  36. package/lib/host/controller/_trace.d.ts.map +1 -0
  37. package/lib/host/controller/_trace.js +14 -0
  38. package/lib/host/controller/_trace.js.map +1 -0
  39. package/lib/host/controller/bridge-run.d.ts +40 -0
  40. package/lib/host/controller/bridge-run.d.ts.map +1 -0
  41. package/lib/host/controller/bridge-run.js +85 -0
  42. package/lib/host/controller/bridge-run.js.map +1 -0
  43. package/lib/host/controller/captures.d.ts +15 -0
  44. package/lib/host/controller/captures.d.ts.map +1 -0
  45. package/lib/host/controller/captures.js +85 -0
  46. package/lib/host/controller/captures.js.map +1 -0
  47. package/lib/host/controller/commits.d.ts +4 -0
  48. package/lib/host/controller/commits.d.ts.map +1 -0
  49. package/lib/host/controller/commits.js +131 -0
  50. package/lib/host/controller/commits.js.map +1 -0
  51. package/lib/host/controller/connections.d.ts +38 -0
  52. package/lib/host/controller/connections.d.ts.map +1 -0
  53. package/lib/host/controller/connections.js +71 -0
  54. package/lib/host/controller/connections.js.map +1 -0
  55. package/lib/host/controller/controller.d.ts +35 -0
  56. package/lib/host/controller/controller.d.ts.map +1 -0
  57. package/lib/host/controller/controller.js +234 -0
  58. package/lib/host/controller/controller.js.map +1 -0
  59. package/lib/host/controller/index.d.ts +30 -0
  60. package/lib/host/controller/index.d.ts.map +1 -0
  61. package/lib/host/controller/index.js +27 -0
  62. package/lib/host/controller/index.js.map +1 -0
  63. package/lib/host/controller/notes.d.ts +26 -0
  64. package/lib/host/controller/notes.d.ts.map +1 -0
  65. package/lib/host/controller/notes.js +44 -0
  66. package/lib/host/controller/notes.js.map +1 -0
  67. package/lib/host/controller/persist.d.ts +16 -0
  68. package/lib/host/controller/persist.d.ts.map +1 -0
  69. package/lib/host/controller/persist.js +98 -0
  70. package/lib/host/controller/persist.js.map +1 -0
  71. package/lib/host/controller/publish.d.ts +4 -0
  72. package/lib/host/controller/publish.d.ts.map +1 -0
  73. package/lib/host/controller/publish.js +56 -0
  74. package/lib/host/controller/publish.js.map +1 -0
  75. package/lib/host/controller/runs.d.ts +80 -0
  76. package/lib/host/controller/runs.d.ts.map +1 -0
  77. package/lib/host/controller/runs.js +394 -0
  78. package/lib/host/controller/runs.js.map +1 -0
  79. package/lib/host/controller/state.d.ts +172 -0
  80. package/lib/host/controller/state.d.ts.map +1 -0
  81. package/lib/host/controller/state.js +2 -0
  82. package/lib/host/controller/state.js.map +1 -0
  83. package/lib/host/controller/windows-run.d.ts +17 -0
  84. package/lib/host/controller/windows-run.d.ts.map +1 -0
  85. package/lib/host/controller/windows-run.js +109 -0
  86. package/lib/host/controller/windows-run.js.map +1 -0
  87. package/lib/host/discovery/candidates.d.ts +47 -0
  88. package/lib/host/discovery/candidates.d.ts.map +1 -0
  89. package/lib/host/discovery/candidates.js +68 -0
  90. package/lib/host/discovery/candidates.js.map +1 -0
  91. package/lib/host/discovery/index.d.ts +19 -0
  92. package/lib/host/discovery/index.d.ts.map +1 -0
  93. package/lib/host/discovery/index.js +19 -0
  94. package/lib/host/discovery/index.js.map +1 -0
  95. package/lib/host/discovery/probe.d.ts +29 -0
  96. package/lib/host/discovery/probe.d.ts.map +1 -0
  97. package/lib/host/discovery/probe.js +155 -0
  98. package/lib/host/discovery/probe.js.map +1 -0
  99. package/lib/host/discovery/scan.d.ts +72 -0
  100. package/lib/host/discovery/scan.d.ts.map +1 -0
  101. package/lib/host/discovery/scan.js +195 -0
  102. package/lib/host/discovery/scan.js.map +1 -0
  103. package/lib/host/flags.d.ts +65 -0
  104. package/lib/host/flags.d.ts.map +1 -0
  105. package/lib/host/flags.js +186 -0
  106. package/lib/host/flags.js.map +1 -0
  107. package/lib/host/kind.d.ts +45 -0
  108. package/lib/host/kind.d.ts.map +1 -0
  109. package/lib/host/kind.js +251 -0
  110. package/lib/host/kind.js.map +1 -0
  111. package/lib/host/manager.d.ts +21 -0
  112. package/lib/host/manager.d.ts.map +1 -0
  113. package/lib/host/manager.js +113 -0
  114. package/lib/host/manager.js.map +1 -0
  115. package/lib/host/migration.d.ts +26 -0
  116. package/lib/host/migration.d.ts.map +1 -0
  117. package/lib/host/migration.js +127 -0
  118. package/lib/host/migration.js.map +1 -0
  119. package/lib/host/platform.d.ts +38 -0
  120. package/lib/host/platform.d.ts.map +1 -0
  121. package/lib/host/platform.js +64 -0
  122. package/lib/host/platform.js.map +1 -0
  123. package/lib/host/plugin-meta.d.ts +21 -0
  124. package/lib/host/plugin-meta.d.ts.map +1 -0
  125. package/lib/host/plugin-meta.js +21 -0
  126. package/lib/host/plugin-meta.js.map +1 -0
  127. package/lib/host/schema.d.ts +361 -0
  128. package/lib/host/schema.d.ts.map +1 -0
  129. package/lib/host/schema.js +196 -0
  130. package/lib/host/schema.js.map +1 -0
  131. package/lib/host/settings.d.ts +28 -0
  132. package/lib/host/settings.d.ts.map +1 -0
  133. package/lib/host/settings.js +91 -0
  134. package/lib/host/settings.js.map +1 -0
  135. package/lib/host/status.d.ts +25 -0
  136. package/lib/host/status.d.ts.map +1 -0
  137. package/lib/host/status.js +45 -0
  138. package/lib/host/status.js.map +1 -0
  139. package/lib/host/tool.d.ts +65 -0
  140. package/lib/host/tool.d.ts.map +1 -0
  141. package/lib/host/tool.js +52 -0
  142. package/lib/host/tool.js.map +1 -0
  143. package/lib/host/types/config.d.ts +101 -0
  144. package/lib/host/types/config.d.ts.map +1 -0
  145. package/lib/host/types/config.js +2 -0
  146. package/lib/host/types/config.js.map +1 -0
  147. package/lib/host/types/executable.d.ts +35 -0
  148. package/lib/host/types/executable.d.ts.map +1 -0
  149. package/lib/host/types/executable.js +9 -0
  150. package/lib/host/types/executable.js.map +1 -0
  151. package/lib/host/types/index.d.ts +24 -0
  152. package/lib/host/types/index.d.ts.map +1 -0
  153. package/lib/host/types/index.js +2 -0
  154. package/lib/host/types/index.js.map +1 -0
  155. package/lib/host/types/plugin.d.ts +38 -0
  156. package/lib/host/types/plugin.d.ts.map +1 -0
  157. package/lib/host/types/plugin.js +10 -0
  158. package/lib/host/types/plugin.js.map +1 -0
  159. package/lib/host/types/services.d.ts +26 -0
  160. package/lib/host/types/services.d.ts.map +1 -0
  161. package/lib/host/types/services.js +9 -0
  162. package/lib/host/types/services.js.map +1 -0
  163. package/lib/host/types/settings.d.ts +180 -0
  164. package/lib/host/types/settings.d.ts.map +1 -0
  165. package/lib/host/types/settings.js +2 -0
  166. package/lib/host/types/settings.js.map +1 -0
  167. package/lib/host/types/stderr.d.ts +51 -0
  168. package/lib/host/types/stderr.d.ts.map +1 -0
  169. package/lib/host/types/stderr.js +9 -0
  170. package/lib/host/types/stderr.js.map +1 -0
  171. package/lib/host/types/windows.d.ts +39 -0
  172. package/lib/host/types/windows.d.ts.map +1 -0
  173. package/lib/host/types/windows.js +9 -0
  174. package/lib/host/types/windows.js.map +1 -0
  175. package/lib/host/values.d.ts +204 -0
  176. package/lib/host/values.d.ts.map +1 -0
  177. package/lib/host/values.js +404 -0
  178. package/lib/host/values.js.map +1 -0
  179. package/lib/host/windows/connect-flags.d.ts +27 -0
  180. package/lib/host/windows/connect-flags.d.ts.map +1 -0
  181. package/lib/host/windows/connect-flags.js +97 -0
  182. package/lib/host/windows/connect-flags.js.map +1 -0
  183. package/lib/host/windows/index.d.ts +31 -0
  184. package/lib/host/windows/index.d.ts.map +1 -0
  185. package/lib/host/windows/index.js +30 -0
  186. package/lib/host/windows/index.js.map +1 -0
  187. package/lib/host/windows/landing.d.ts +47 -0
  188. package/lib/host/windows/landing.d.ts.map +1 -0
  189. package/lib/host/windows/landing.js +174 -0
  190. package/lib/host/windows/landing.js.map +1 -0
  191. package/lib/host/windows/link.d.ts +11 -0
  192. package/lib/host/windows/link.d.ts.map +1 -0
  193. package/lib/host/windows/link.js +52 -0
  194. package/lib/host/windows/link.js.map +1 -0
  195. package/lib/host/windows/paths.d.ts +64 -0
  196. package/lib/host/windows/paths.d.ts.map +1 -0
  197. package/lib/host/windows/paths.js +148 -0
  198. package/lib/host/windows/paths.js.map +1 -0
  199. package/lib/host/windows/run.d.ts +74 -0
  200. package/lib/host/windows/run.d.ts.map +1 -0
  201. package/lib/host/windows/run.js +211 -0
  202. package/lib/host/windows/run.js.map +1 -0
  203. package/lib/host/windows/spawn.d.ts +22 -0
  204. package/lib/host/windows/spawn.d.ts.map +1 -0
  205. package/lib/host/windows/spawn.js +73 -0
  206. package/lib/host/windows/spawn.js.map +1 -0
  207. package/lib/index.d.ts +102 -0
  208. package/lib/index.d.ts.map +1 -0
  209. package/lib/index.js +102 -636
  210. package/lib/index.js.map +1 -0
  211. package/locale/en.json +6 -0
  212. package/locale/zh.json +6 -0
  213. package/package.json +57 -14
  214. package/cordis.patch.yml +0 -5
@@ -0,0 +1,195 @@
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 the bridge *launches* has to be a Linux binary.
17
+ * Launching the Windows chrome.exe through the WSL interop layer fails:
18
+ * chrome-devtools-mcp connects with `pipe: true` (inherited fd 3/4), and
19
+ * Windows-side processes cannot receive those pipes from WSL; the WebSocket
20
+ * fallback hard-codes 127.0.0.1 in the DevToolsActivePort file, unreachable
21
+ * across the WSL2 NAT bridge. Verified empirically 2025-09-19 (.probe/). What
22
+ * the Windows side *is* good for is connect mode, so on a WSL host the Windows
23
+ * executables join the candidate list as `blockedForPlatform` answers it —
24
+ * visible, selectable, never spawned — and the run that drives them is the
25
+ * **Prelaunch Windows Chrome** one. Never spawn a blocked candidate.
26
+ */
27
+ import { flagsSkipProbe } from "../flags.js";
28
+ import { firstLine } from "../status.js";
29
+ import { readConfigField } from "../values.js";
30
+ import { windowsPathToMount } from "../windows/paths.js";
31
+ import { defaultChromePaths } from "./candidates.js";
32
+ import { identity, presentOnDisk, probeExecutable } from "./probe.js";
33
+ /**
34
+ * What one run probes: every candidate it has — the row-config candidate list,
35
+ * the paths the saved rows carry, and the current selection (see
36
+ * {@link chromeExecutableCandidates}) — probed in that order.
37
+ *
38
+ * A candidate that runs answers with its `--version` line; one that is present
39
+ * but not runnable (bad binary, a probe that timed out) keeps its place in the
40
+ * list carrying the failure, so a broken pin stays visible instead of vanishing
41
+ * into a red dot.
42
+ *
43
+ * - absent / not executable → dropped without a spawn,
44
+ * - `blockedForPlatform` answers non-empty → **no spawn**: the candidate keeps
45
+ * its place carrying that reason as a `note`, never as a failure (the one case
46
+ * is a Windows `chrome.exe` on a WSL host, whose probe would start a browser
47
+ * instance it can never drive — see {@link WSL_WINDOWS_LAUNCH_ERROR}),
48
+ * - two spellings of the same binary collapse into the first one seen.
49
+ *
50
+ * An empty candidate list resolves `[]` (nothing probed: unknown platform, or a
51
+ * host patched down to nothing).
52
+ *
53
+ * @param candidates - candidate executable paths.
54
+ * @param blockedForPlatform - answers a reason for a candidate this host must
55
+ * never exec, `""` for one it may probe.
56
+ */
57
+ export async function scanChromeExecutables(candidates, blockedForPlatform = () => "") {
58
+ const list = Array.isArray(candidates) ? candidates : [];
59
+ const statuses = [];
60
+ const seen = new Set();
61
+ for (const candidate of list) {
62
+ const path = String(candidate ?? "").trim();
63
+ if (path === "")
64
+ continue;
65
+ const blocked = blockedForPlatform(path);
66
+ if (blocked !== "") {
67
+ // Never spawned: what a blocked candidate would do is start a
68
+ // browser this host could not drive. It keeps its place on the list
69
+ // carrying that reason as a **note** — what gets reported is what
70
+ // this host could not do with the path, not whether it is there, and
71
+ // reporting it as a failure would read as a broken executable.
72
+ //
73
+ // The seen key folds through the interop mount, because the same
74
+ // executable reaches this list in either spelling: the Windows one
75
+ // the locate answers, and the mount one a saved row or the row config
76
+ // can carry (the only spelling the WSL side can stat). One executable
77
+ // answers once, under the first spelling seen.
78
+ const mounted = windowsPathToMount(path);
79
+ const key = `blocked\u0000${identity(mounted !== "" ? mounted : path)}`;
80
+ if (seen.has(key))
81
+ continue;
82
+ seen.add(key);
83
+ statuses.push({ path, version: "", error: "", note: blocked });
84
+ continue;
85
+ }
86
+ if (!presentOnDisk(path))
87
+ continue;
88
+ try {
89
+ const version = await probeExecutable(path);
90
+ const key = `${identity(path)}\u0000${version}`;
91
+ if (seen.has(key))
92
+ continue;
93
+ seen.add(key);
94
+ statuses.push({ path, version, error: "", note: "" });
95
+ }
96
+ catch (error) {
97
+ const code = (error instanceof Error && typeof error.code === "string")
98
+ ? error.code
99
+ : "";
100
+ if (code === "ENOENT")
101
+ continue;
102
+ const key = identity(path);
103
+ if (seen.has(key))
104
+ continue;
105
+ seen.add(key);
106
+ statuses.push({
107
+ path,
108
+ version: "",
109
+ error: firstLine(error instanceof Error ? error.message : String(error)),
110
+ note: ""
111
+ });
112
+ }
113
+ }
114
+ return statuses;
115
+ }
116
+ /**
117
+ * Discover usable Google Chrome executables when nothing is fixed: probe every
118
+ * candidate and report the first runnable one. Kept for its `Promise<string>`
119
+ * contract (`src/index.ts` re-export, tests, diagnostics).
120
+ * @param candidatePaths - candidate executable paths (default: platform list).
121
+ * @param blockedForPlatform - answers a reason for a candidate this host must
122
+ * never exec, `""` for one it may probe.
123
+ * @returns the discovered executable version line.
124
+ */
125
+ export async function discoverChrome(candidatePaths, blockedForPlatform = () => "") {
126
+ const candidates = (Array.isArray(candidatePaths) ? candidatePaths : defaultChromePaths())
127
+ .map((candidate) => String(candidate ?? "").trim())
128
+ .filter((candidate) => candidate !== "");
129
+ if (candidates.length === 0)
130
+ return "";
131
+ const found = await scanChromeExecutables(candidates, blockedForPlatform);
132
+ for (const status of found) {
133
+ if (status.version !== "" && status.error === "")
134
+ return status.version;
135
+ }
136
+ const broken = found.find((status) => status.error !== "");
137
+ if (broken !== void 0)
138
+ throw new Error(broken.error);
139
+ // A note is the other half of "nothing answered": the candidate is there, it
140
+ // is simply not launchable as a local executable from this host (the one
141
+ // case is a Windows executable under WSL), and the note names the run that
142
+ // drives it.
143
+ const noted = found.find((status) => status.note !== "");
144
+ if (noted !== void 0) {
145
+ throw new Error(`Chrome executable not found: no executable detected for this host (checked: ${candidates.join(", ")}); ${noted.note}`);
146
+ }
147
+ throw new Error(`Chrome executable not found: no executable detected (checked: ${candidates.join(", ")})`);
148
+ }
149
+ /**
150
+ * One check run — the public "did we find a runnable Chrome?" question:
151
+ *
152
+ * - `chromePath` non-empty → probe that executable (ENOENT → "Chrome
153
+ * executable not found: <path>"; non-zero → first stderr/stdout line;
154
+ * success → the version line).
155
+ * - `chromePath` empty → run the scan over the candidate list (row config
156
+ * `chromePaths`, default {@link defaultChromePaths}) and report the first
157
+ * runnable entry. Nothing usable → the known executable-missing error;
158
+ * only-present-but-broken entries → that entry's failure.
159
+ * - the extra flags leave the check mute: they declare a connect mode
160
+ * (`--browserUrl` / `--browser-url` / `-u`, `--wsEndpoint` /
161
+ * `--ws-endpoint` / `-w`, `--autoConnect` / `--auto-connect`), name a
162
+ * config file (`--config`), or fix another `--channel` than the `stable`
163
+ * the candidate list models → resolve "": there is no local executable
164
+ * this check could honestly answer for.
165
+ * - `blockedForPlatform` answers non-empty for what is selected → resolve "" with
166
+ * **no spawn**. A Windows `chrome.exe` on a WSL host is the case: its
167
+ * `--version` probe answers (which is why the selection looks healthy) but
168
+ * answering means attaching to the Windows browser session, and that *starts*
169
+ * a browser instance no tool call could drive
170
+ * ({@link WSL_WINDOWS_LAUNCH_ERROR}).
171
+ *
172
+ * A run that probes **nothing** (no candidates, a connect mode, a config file
173
+ * or another channel standing in for the local executable, or a blocked path)
174
+ * resolves "" — callers must treat that as "no evidence", never as health.
175
+ *
176
+ * @param entry - validated {@link ChromeMcpConfig}.
177
+ * @param extraFlags - the flags list the bridge currently launches with;
178
+ * inspected for the entries that leave the check mute.
179
+ * @param blockedForPlatform - answers a reason for a path this host must never
180
+ * exec, `""` for one it may probe.
181
+ * @returns the executable version line, or "" when nothing is probed.
182
+ */
183
+ export function checkChrome(entry, extraFlags, blockedForPlatform = () => "") {
184
+ // The two config fields read here are volatile, so what they carry is either a
185
+ // reference or the value a caller handed in explicitly.
186
+ const target = readConfigField(entry.chromePath, "").trim();
187
+ if (target !== "")
188
+ return blockedForPlatform(target) !== "" ? Promise.resolve("") : probeExecutable(target);
189
+ const flags = extraFlags === void 0 ? readConfigField(entry.extraFlags, []) : extraFlags;
190
+ if (flagsSkipProbe(flags)) {
191
+ return Promise.resolve("");
192
+ }
193
+ return discoverChrome(entry.chromePaths, blockedForPlatform);
194
+ }
195
+ //# 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,65 @@
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
+ /**
34
+ * True when one extraFlag declares a connect mode (the bridge will not launch a
35
+ * local executable). Upstream spellings (docs/configuration.md): the two URL
36
+ * options — `--browserUrl`/`--browser-url`/`-u` and
37
+ * `--wsEndpoint`/`--ws-endpoint`/`-w` — plus `--autoConnect`/`--auto-connect`,
38
+ * which attaches to an already-running Chrome (Chrome 144+) instead of starting
39
+ * one. Each form counts with its value inline (`=`), carried as the following
40
+ * entry (the whitespace-split env source's spelling), or bare.
41
+ */
42
+ export declare function carriesConnectionMode(flag: string): boolean;
43
+ /** True when one extraFlag names a config file. */
44
+ export declare function carriesConfigFile(flag: unknown): boolean;
45
+ /** True when one extraFlag fixes the update channel to something other than
46
+ * `stable` (the default the candidate list models). `next` is the entry that
47
+ * follows a bare `--channel`; a value equal to the default is not a skip. */
48
+ export declare function carriesOtherChannel(flag: unknown, next?: unknown): boolean;
49
+ /** True when an executable probe could not answer here, whatever the host
50
+ * carries: the bridge connects instead of launching (connect mode), the
51
+ * executable it runs came from a config file, or the channel it looks in is
52
+ * not the `stable` one the candidate list models. A check that ran **no**
53
+ * probe answers `""` — *no evidence*, never health: it must not clear
54
+ * `lastError` nor the known `chromeMissing` state. */
55
+ export declare function flagsSkipProbe(flags: unknown): boolean;
56
+ /** True when any entry of a flags list declares connect mode — the connect
57
+ * half that answers the live `carriesConnectionMode` mirror, keys the pill
58
+ * relabel on, and drops `--executablePath` from the argv. For what spares the
59
+ * *executable check* there is the wider {@link flagsSkipProbe}: a config file
60
+ * and a non-`stable` channel also leave the probe mute, while the bridge still
61
+ * launches a local executable. */
62
+ export declare function flagsSkipCheck(flags: unknown): boolean;
63
+ /** True when two flags lists are element-wise equal (flags are arrays). */
64
+ export declare function sameFlags(a: unknown, b: unknown): boolean;
65
+ //# sourceMappingURL=flags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flags.d.ts","sourceRoot":"","sources":["../../src/host/flags.ts"],"names":[],"mappings":"AAsBA;;;;;;;;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;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AAQD,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAExD;AAQD;;6EAE6E;AAC7E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAa1E;AAED;;;;;sDAKsD;AACtD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAStD;AAED;;;;;kCAKkC;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,186 @@
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`; the connect group `--browserUrl`/`--browser-url`/
9
+ * `-u`, `--wsEndpoint`/`--ws-endpoint`/`-w`, `--autoConnect`/`--auto-connect`;
10
+ * plus the probe-skipping `--config` and `--channel`).
11
+ *
12
+ * One rule has since hardened: pinning the executable by flag is a second
13
+ * source of truth for the same lever the executable picker owns, so a
14
+ * user-authored list may not carry it (`validateExtraFlags` rejects it), and
15
+ * the row config's copy gets folded into `chromePath` instead of reaching argv
16
+ * as a second opinion.
17
+ */
18
+ import { CONTROL_PATTERN } from "./constants.js";
19
+ /** One executable-path flag, upstream spellings, with or without `=`. */
20
+ const EXECUTABLE_PATH_FLAG = /^(?:--executablePath|--executable-path|-e)(?:=|(?=\s)|$)/iu;
21
+ /**
22
+ * Validate a user-authored extraFlags list: a plain array of flag strings
23
+ * carrying no control characters (argv is execve'd without a shell), and no
24
+ * executable-path flag — the executable is picked in the card's selector, so
25
+ * letting a flag pin one would put a second source of truth over the bridge
26
+ * argv. Throws with the offending entry so the settings layer can surface it.
27
+ * @param value - candidate flags array.
28
+ * @returns true when valid.
29
+ */
30
+ export function validateExtraFlags(value) {
31
+ if (!Array.isArray(value)) {
32
+ throw new Error("extraFlags must be an array of strings");
33
+ }
34
+ for (const flag of value) {
35
+ if (typeof flag !== "string" || flag === "") {
36
+ throw new Error("extraFlags entries must be non-empty strings");
37
+ }
38
+ if (CONTROL_PATTERN.test(flag)) {
39
+ throw new Error(`extraFlags entry "${flag}" contains control characters`);
40
+ }
41
+ if (carriesExecutablePath(flag)) {
42
+ throw new Error(`extraFlags entry "${flag}" selects the Chrome executable — pick it in the Chrome executable picker instead`);
43
+ }
44
+ }
45
+ return true;
46
+ }
47
+ /** True when a flag selects the Chrome executable (upstream flags:
48
+ * `--executablePath` / `--executable-path` / `-e`, with or without `=`).
49
+ * No longer an accepted user flag (see {@link validateExtraFlags}): it stays
50
+ * here for the row-config fold ({@link extractExecutablePathFlag}) and the
51
+ * argv guard. */
52
+ export function carriesExecutablePath(flag) {
53
+ return typeof flag === "string" && EXECUTABLE_PATH_FLAG.test(flag);
54
+ }
55
+ /**
56
+ * Read the path a legacy `--executablePath` carries in the **row-config** flags
57
+ * list: the `=` spelling and the separated spelling both count, first entry
58
+ * wins, "" when nothing pins a path.
59
+ *
60
+ * The card's picker owns the executable now, so a row-config pin is not
61
+ * honored as a flag: it becomes the row-config source of the selection and gets
62
+ * stripped out of argv (see {@link stripExecutablePathFlags}).
63
+ */
64
+ export function extractExecutablePathFlag(flags) {
65
+ if (!Array.isArray(flags))
66
+ return "";
67
+ for (let index = 0; index < flags.length; index++) {
68
+ const flag = flags[index];
69
+ if (typeof flag !== "string" || !carriesExecutablePath(flag))
70
+ continue;
71
+ const eq = flag.indexOf("=");
72
+ if (eq !== -1)
73
+ return flag.slice(eq + 1).trim();
74
+ const next = flags[index + 1];
75
+ return typeof next === "string" && next.trim() !== "" ? next.trim() : "";
76
+ }
77
+ return "";
78
+ }
79
+ /** Drop every entry that pins an executable from a flags list — paired with
80
+ * {@link extractExecutablePathFlag} so a legacy profile keeps its path as a
81
+ * selection source instead of reaching argv as a second source of truth.
82
+ * A `--flag <path>` spelling consumes the following entry; a flag-looking next
83
+ * entry keeps it (nothing was meant as the value). */
84
+ export function stripExecutablePathFlags(flags) {
85
+ if (!Array.isArray(flags))
86
+ return [];
87
+ const stripped = [];
88
+ let awaitingValue = false;
89
+ for (const flag of flags) {
90
+ if (typeof flag !== "string")
91
+ continue;
92
+ if (carriesExecutablePath(flag)) {
93
+ awaitingValue = !flag.includes("=");
94
+ continue;
95
+ }
96
+ if (awaitingValue && !flag.startsWith("-"))
97
+ continue;
98
+ awaitingValue = false;
99
+ stripped.push(flag);
100
+ }
101
+ return stripped;
102
+ }
103
+ /**
104
+ * True when one extraFlag declares a connect mode (the bridge will not launch a
105
+ * local executable). Upstream spellings (docs/configuration.md): the two URL
106
+ * options — `--browserUrl`/`--browser-url`/`-u` and
107
+ * `--wsEndpoint`/`--ws-endpoint`/`-w` — plus `--autoConnect`/`--auto-connect`,
108
+ * which attaches to an already-running Chrome (Chrome 144+) instead of starting
109
+ * one. Each form counts with its value inline (`=`), carried as the following
110
+ * entry (the whitespace-split env source's spelling), or bare.
111
+ */
112
+ export function carriesConnectionMode(flag) {
113
+ return /^(?:--(?:auto[-]?connect|browser[-]?url|ws[-]?endpoint)(?:=|(?=\s)|$)|-[uw]\b)/iu.test(flag);
114
+ }
115
+ /** One config-file flag, `--config <file>` (also matched for the
116
+ * `--config-path` spelling). A JSON config can fix the executable and the
117
+ * connect mode itself, so the bridge argv no longer states locally what will
118
+ * run — the check would only guess. */
119
+ const CONFIG_FILE_FLAG = /^--config(?:-path)?(?:=|(?=\s)|$)/iu;
120
+ /** True when one extraFlag names a config file. */
121
+ export function carriesConfigFile(flag) {
122
+ return typeof flag === "string" && CONFIG_FILE_FLAG.test(flag);
123
+ }
124
+ /** One `--channel` flag. Its value picks where upstream looks for a browser
125
+ * (`canary`/`dev`/`beta`/`stable`); the check's own candidate list models only
126
+ * `stable`, so any other value makes it answer "not found" about a browser
127
+ * living in another channel. */
128
+ const CHANNEL_FLAG = /^--channel(?:=|(?=\s)|$)/iu;
129
+ /** True when one extraFlag fixes the update channel to something other than
130
+ * `stable` (the default the candidate list models). `next` is the entry that
131
+ * follows a bare `--channel`; a value equal to the default is not a skip. */
132
+ export function carriesOtherChannel(flag, next) {
133
+ if (typeof flag !== "string" || !CHANNEL_FLAG.test(flag))
134
+ return false;
135
+ const eq = flag.indexOf("=");
136
+ let value;
137
+ if (eq !== -1) {
138
+ value = flag.slice(eq + 1).trim();
139
+ }
140
+ else {
141
+ const whitespace = /\s/u.exec(flag);
142
+ if (whitespace !== null)
143
+ value = flag.slice(whitespace.index + 1).trim();
144
+ else if (typeof next === "string" && !next.startsWith("-"))
145
+ value = next.trim();
146
+ else
147
+ return false;
148
+ }
149
+ return value !== "" && value.toLowerCase() !== "stable";
150
+ }
151
+ /** True when an executable probe could not answer here, whatever the host
152
+ * carries: the bridge connects instead of launching (connect mode), the
153
+ * executable it runs came from a config file, or the channel it looks in is
154
+ * not the `stable` one the candidate list models. A check that ran **no**
155
+ * probe answers `""` — *no evidence*, never health: it must not clear
156
+ * `lastError` nor the known `chromeMissing` state. */
157
+ export function flagsSkipProbe(flags) {
158
+ if (!Array.isArray(flags))
159
+ return false;
160
+ for (let index = 0; index < flags.length; index += 1) {
161
+ const flag = flags[index];
162
+ if (typeof flag !== "string")
163
+ continue;
164
+ if (carriesConnectionMode(flag) || carriesConfigFile(flag))
165
+ return true;
166
+ if (CHANNEL_FLAG.test(flag) && carriesOtherChannel(flag, flags[index + 1]))
167
+ return true;
168
+ }
169
+ return false;
170
+ }
171
+ /** True when any entry of a flags list declares connect mode — the connect
172
+ * half that answers the live `carriesConnectionMode` mirror, keys the pill
173
+ * relabel on, and drops `--executablePath` from the argv. For what spares the
174
+ * *executable check* there is the wider {@link flagsSkipProbe}: a config file
175
+ * and a non-`stable` channel also leave the probe mute, while the bridge still
176
+ * launches a local executable. */
177
+ export function flagsSkipCheck(flags) {
178
+ return Array.isArray(flags) && flags.some((flag) => typeof flag === "string" && carriesConnectionMode(flag));
179
+ }
180
+ /** True when two flags lists are element-wise equal (flags are arrays). */
181
+ export function sameFlags(a, b) {
182
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)
183
+ return false;
184
+ return a.every((flag, index) => flag === b[index]);
185
+ }
186
+ //# 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,45 @@
1
+ import type { KindOption, McpKind, ServerEntry } from "@comecaramelos/dsh-mcp-manager/api";
2
+ import type { Controller } from "./controller/index.js";
3
+ /** Split one `lines` field's value into its flags. Missing/blank answers nothing
4
+ * — the entry carries no own answer, so the caller falls through to the row. */
5
+ export declare function parseFlagLines(value: unknown): string[] | undefined;
6
+ /** Join one flags list back into a `lines` field value (round-trips with
7
+ * {@link parseFlagLines}). */
8
+ export declare function joinFlagLines(flags: readonly string[]): string;
9
+ /**
10
+ * What the executable field offers: the saved rows first, then every path the
11
+ * last scan reported, then the Windows-side executables a WSL host carries, then
12
+ * the path a live connection actually launches with — the running path is the
13
+ * answer the Host knows best, and it may not be a saved row yet. A stored pick
14
+ * the choices stop carrying stays offered by the card itself, so it never
15
+ * silently becomes another one.
16
+ */
17
+ export declare function executableChoices(controller: Controller): readonly KindOption[];
18
+ /** The executable one entry launches with: its own pick, else what the row's
19
+ * layers resolve (the user layer, then the row config with a legacy
20
+ * `--executablePath` folded in) — never a scan answer and never a re-resolve. */
21
+ export declare function entryExecutable(entry: ServerEntry, controller: Controller): string;
22
+ /** The flags one entry launches with: its own `lines` field, else the row's
23
+ * resolved precedence (user layer > `DSH_CHROME_MCP_FLAGS` > row config > the
24
+ * schema default). */
25
+ export declare function entryExtraFlags(entry: ServerEntry, controller: Controller): string[];
26
+ /** The console-output mode one entry runs with: its own pick, else the row's
27
+ * answer. Never a third state. The field is a toggle (`"true"` = reduce = log
28
+ * file); the `log`/`console` it stored while it was a choice still read. */
29
+ export declare function entryStderrMode(entry: ServerEntry, controller: Controller): "log" | "console";
30
+ /** The `chrome` kind: the local `chrome-devtools-mcp` bridge — what the row used
31
+ * to start for itself, now as one of the manager's connections. */
32
+ export declare function createChromeKind(controller: Controller): McpKind;
33
+ /** The `chrome-windows` kind: the Windows browser driven through the WSL interop
34
+ * mount. `resolve` runs the prelaunch itself — locate, prereq, free port,
35
+ * launch, wait for the bind — and answers the local `chrome-devtools-mcp` in
36
+ * connect mode against that port. The port speaks no MCP; the MCP stays the
37
+ * local process. Off WSL the entry is refused, with the answer the card shows. */
38
+ export declare function createChromeWindowsKind(controller: Controller): McpKind;
39
+ /** The kinds this host can answer, in registration order — `chrome` first,
40
+ * because it is the answer a standalone config translates into by default
41
+ * (./migration.ts). `chrome-windows` is offered on WSL only: anywhere else its
42
+ * `resolve` could only refuse, so the picker never lists it there (a native
43
+ * Windows host drives its own Chrome through `chrome`). */
44
+ export declare function createChromeKinds(controller: Controller): McpKind[];
45
+ //# sourceMappingURL=kind.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kind.d.ts","sourceRoot":"","sources":["../../src/host/kind.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAsB,WAAW,EAAE,MAAM,oCAAoC,CAAC;AAC/G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD;gFACgF;AAChF,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAInE;AAED;8BAC8B;AAC9B,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAE9D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,UAAU,EAAE,CAe/E;AAED;;iFAEiF;AACjF,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,GAAG,MAAM,CAIlF;AAED;;sBAEsB;AACtB,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,GAAG,MAAM,EAAE,CAIpF;AAED;;4EAE4E;AAC5E,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,GAAG,KAAK,GAAG,SAAS,CAM7F;AAwCD;mEACmE;AACnE,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAgDhE;AAED;;;;kFAIkF;AAClF,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CA8CvE;AAED;;;;2DAI2D;AAC3D,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,EAAE,CAEnE"}