@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,109 @@
1
+ /**
2
+ * Controller — the one Windows Chrome run.
3
+ *
4
+ * The whole Windows path the **Prelaunch Windows Chrome** surface drives (the
5
+ * card button, the `prelaunch_windows_chrome` tool, and the async `resolve` of a
6
+ * live `chrome-windows` connection), sequenced here against the injected run
7
+ * half (./run.ts in ../windows). The run never kills what it started; everything
8
+ * it answers lands in the live mirror's `windowsChromeStatus`, and the run
9
+ * result is handed back to the caller — in the component model the browser is
10
+ * driven by a connection, not by a bridge this row owns, so a successful run
11
+ * writes no flag anywhere: the debugging URL belongs to the connection's own
12
+ * answer, not to this row's configuration.
13
+ *
14
+ * Re-entry is cheap by construction: when a previous run already left the live
15
+ * mirror connected, the URL it stated rides into `currentFlags`, and the
16
+ * underlying run reuses that port when the browser behind it still answers —
17
+ * so re-running is idempotent, never a second browser.
18
+ */
19
+ import { firstLine } from "../status.js";
20
+ import { isWindowsExecutablePath } from "../platform.js";
21
+ import { windowsChromeProjectDir, withBrowserUrlFlag } from "../windows/index.js";
22
+ import { resolveLaunchFlags, resolveSelection } from "../values.js";
23
+ import { publishLive } from "./publish.js";
24
+ /**
25
+ * One **Prelaunch Windows Chrome** run. When the host is not WSL there is simply
26
+ * nothing to drive and the answer is `not-applicable`; otherwise the state moves
27
+ * through `launching` while the run (locate, prereq, launch, port) settles, and
28
+ * the settled state is mirrored before the run is returned.
29
+ */
30
+ export async function runWindowsChrome(controller) {
31
+ const { state } = controller;
32
+ if (!controller.wslHost) {
33
+ state.live.windowsChromeStatus = { state: "not-applicable", port: 0, error: "" };
34
+ publishLive(controller);
35
+ return { state: "not-applicable", port: 0, url: "", profileDir: "", error: "" };
36
+ }
37
+ state.live.windowsChromeStatus = { state: "launching", port: state.live.windowsChromeStatus.port, error: "" };
38
+ publishLive(controller);
39
+ let currentFlags = resolveLaunchFlags(state.source(), controller.launchFlags);
40
+ // A run answering from a mirror that stands connected carries its own URL in
41
+ // — that is what makes re-entry (tool re-run, pool re-prepare) idempotent:
42
+ // the underlying run reuses the live port instead of launching again.
43
+ if (state.live.windowsChromeStatus.state === "connected" && state.live.windowsChromeStatus.port > 0) {
44
+ currentFlags = withBrowserUrlFlag(currentFlags, `http://127.0.0.1:${state.live.windowsChromeStatus.port}`);
45
+ }
46
+ // The workspace that carries the run's `.chrome` view: the row-config `cwd`,
47
+ // else the live session's workspace — the run answers the GUI the user is
48
+ // driving, not the directory `dsh web` happened to be launched from (a view
49
+ // rooted at `~` links `~/.chrome`) — else the host's own cwd.
50
+ const projectDir = windowsChromeProjectDir(controller.config.cwd, controller.ctx.get("sessions"), process.cwd());
51
+ // The executable the picker selected, when that selection is a Windows one:
52
+ // what the run launches is then exactly what the card named, not the first
53
+ // location the run happens to find. Nothing else stands in — a selection
54
+ // that is not there answers by naming it — while a selection naming no
55
+ // Windows executable (nothing picked, or a local one) leaves the run's own
56
+ // locate in charge, exactly as it was.
57
+ const selected = resolveSelection(state.source()).path;
58
+ const candidates = isWindowsExecutablePath(selected) ? [selected] : void 0;
59
+ let result;
60
+ try {
61
+ result = await controller.windowsChrome({
62
+ cwd: projectDir,
63
+ currentFlags,
64
+ ...(candidates === void 0 ? {} : { candidates })
65
+ });
66
+ }
67
+ catch (error) {
68
+ result = { state: "launch-failed", port: 0, url: "", profileDir: "", error: firstLine(error instanceof Error ? error.message : String(error)) };
69
+ }
70
+ state.live.windowsChromeStatus = { state: result.state, port: result.port, error: firstLine(result.error) };
71
+ if (result.state === "connected") {
72
+ if (result.profileDir !== "") {
73
+ if (result.profileLink === "kept") {
74
+ // A real `.chrome` directory already sits at the view's spot:
75
+ // kept untouched, the link never clobbers what is already there
76
+ // — say it once, not on every run.
77
+ if (!state.profileLinkKeptShown) {
78
+ state.profileLinkKeptShown = true;
79
+ controller.ctx.logger.warn(`dsh-chrome-mcp(${controller.config.serverName}): ${projectDir}/.chrome is an existing directory — the Windows profile stays at ${result.profileDir}, not linked into the checkout`);
80
+ }
81
+ }
82
+ else {
83
+ controller.ctx.logger.info(`dsh-chrome-mcp(${controller.config.serverName}): Windows Chrome profile ${result.profileDir}, workspace view ${projectDir}/.chrome`);
84
+ }
85
+ }
86
+ state.live.lastError = "";
87
+ publishLive(controller);
88
+ return { state: result.state, port: result.port, url: result.url, profileDir: result.profileDir, error: "" };
89
+ }
90
+ state.live.lastError = firstLine(result.error);
91
+ publishLive(controller);
92
+ controller.ctx.logger.warn(`dsh-chrome-mcp(${controller.config.serverName}): Windows Chrome run did not connect: ${state.live.lastError}`);
93
+ return { state: result.state, port: result.port, url: result.url, profileDir: result.profileDir, error: state.live.lastError };
94
+ }
95
+ /**
96
+ * The kind-side half of the run: a live `chrome-windows` connection's async
97
+ * `resolve` drives the launch through the same one-run-at-a-time chain the
98
+ * button uses, and gets the run result back to turn into the connect-mode
99
+ * stdio config.
100
+ */
101
+ export async function prelaunchWindowsForConnection(controller) {
102
+ const { state } = controller;
103
+ const off = "off";
104
+ const failed = "launch-failed";
105
+ return state.runs
106
+ .then(async () => (state.disposed ? { state: off, port: 0, url: "", profileDir: "", error: "the component was disposed" } : runWindowsChrome(controller)))
107
+ .catch((error) => ({ state: failed, port: 0, url: "", profileDir: "", error: firstLine(error instanceof Error ? error.message : String(error)) }));
108
+ }
109
+ //# sourceMappingURL=windows-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-run.js","sourceRoot":"","sources":["../../../src/host/controller/windows-run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Chrome discovery — the candidate list.
3
+ *
4
+ * Where discovery looks before anything is picked: the platform's stable-channel
5
+ * Chrome locations (mirroring upstream puppeteer's) and the ordered candidate
6
+ * list one run folds together — row-config `chromePaths`, then whatever else this
7
+ * host carries (on a WSL host: the Windows-side executables answering through the
8
+ * interop mount, never spawned from here), then the saved rows' ids, then the
9
+ * selection. The probes over that list live in ./scan.ts; the `--version` probe
10
+ * itself in ./probe.ts.
11
+ */
12
+ import type { ChromeMcpConfig } from "../types/index.js";
13
+ /**
14
+ * Google Chrome stable-channel locations probed by discovery when
15
+ * `chromePath` is empty — mirrors the upstream (puppeteer) system-channel
16
+ * resolution. The Windows-side locations a WSL host reaches through the interop
17
+ * mount are deliberately not mixed into the *platform* list (their spelling
18
+ * belongs to the other side of the boundary); a WSL host's run folds them in
19
+ * separately, as the candidates it offers without probing (see
20
+ * `chromeExecutableCandidates`' `extraCandidates` and the never-spawn rule in
21
+ * ./scan.ts). Unknown platforms probe nothing.
22
+ */
23
+ export declare const DEFAULT_CHROME_PATHS: {
24
+ linux: string[];
25
+ darwin: string[];
26
+ win32: string[];
27
+ };
28
+ /** The default discovery candidate list for one platform; [] probes nothing. */
29
+ export declare function defaultChromePaths(platform?: NodeJS.Platform): string[];
30
+ /**
31
+ * Every path one executable run probes: the row-config candidate list (default
32
+ * the platform list), then whatever else this host carries, then the ids the
33
+ * saved rows carry, then the current selection — deduplicated, in this order,
34
+ * so the list reads "what the profile configures, then what the machine carries,
35
+ * then what the card saved, then what runs".
36
+ * @param entry - validated row config (`chromePaths` is the candidate list).
37
+ * @param savedIds - the saved rows' ids, in row order (see ./catalog.ts).
38
+ * @param effectivePath - the currently selected path, always kept in the list.
39
+ * @param extraCandidates - what this host carries beyond the configured list:
40
+ * the Windows-side executables a WSL host reaches through the interop mount.
41
+ * They join the list so the **Prelaunch Windows Chrome** run drives what the
42
+ * picker picked rather than what it happens to locate first — and, offered
43
+ * without being probed, they answer a note and never a version (see the
44
+ * `blockedForPlatform` answer threaded through ./scan.ts).
45
+ */
46
+ export declare function chromeExecutableCandidates(entry: Pick<ChromeMcpConfig, "chromePaths">, savedIds?: readonly string[], effectivePath?: string, extraCandidates?: readonly string[]): string[];
47
+ //# sourceMappingURL=candidates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"candidates.d.ts","sourceRoot":"","sources":["../../../src/host/discovery/candidates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB;;;;CAahC,CAAC;AAEF,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,MAAM,EAAE,CAGzF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,0BAA0B,CACtC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,EAC3C,QAAQ,GAAE,SAAS,MAAM,EAAO,EAChC,aAAa,SAAK,EAClB,eAAe,GAAE,SAAS,MAAM,EAAO,GACxC,MAAM,EAAE,CAiBV"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Google Chrome stable-channel locations probed by discovery when
3
+ * `chromePath` is empty — mirrors the upstream (puppeteer) system-channel
4
+ * resolution. The Windows-side locations a WSL host reaches through the interop
5
+ * mount are deliberately not mixed into the *platform* list (their spelling
6
+ * belongs to the other side of the boundary); a WSL host's run folds them in
7
+ * separately, as the candidates it offers without probing (see
8
+ * `chromeExecutableCandidates`' `extraCandidates` and the never-spawn rule in
9
+ * ./scan.ts). Unknown platforms probe nothing.
10
+ */
11
+ export const DEFAULT_CHROME_PATHS = {
12
+ linux: [
13
+ "/opt/google/chrome/chrome",
14
+ "/usr/bin/google-chrome",
15
+ "/usr/bin/google-chrome-stable",
16
+ "/usr/local/bin/google-chrome",
17
+ "google-chrome"
18
+ ],
19
+ darwin: ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"],
20
+ win32: [
21
+ "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
22
+ "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"
23
+ ]
24
+ };
25
+ /** The default discovery candidate list for one platform; [] probes nothing. */
26
+ export function defaultChromePaths(platform = process.platform) {
27
+ const candidates = DEFAULT_CHROME_PATHS[platform];
28
+ return Array.isArray(candidates) ? [...candidates] : [];
29
+ }
30
+ /**
31
+ * Every path one executable run probes: the row-config candidate list (default
32
+ * the platform list), then whatever else this host carries, then the ids the
33
+ * saved rows carry, then the current selection — deduplicated, in this order,
34
+ * so the list reads "what the profile configures, then what the machine carries,
35
+ * then what the card saved, then what runs".
36
+ * @param entry - validated row config (`chromePaths` is the candidate list).
37
+ * @param savedIds - the saved rows' ids, in row order (see ./catalog.ts).
38
+ * @param effectivePath - the currently selected path, always kept in the list.
39
+ * @param extraCandidates - what this host carries beyond the configured list:
40
+ * the Windows-side executables a WSL host reaches through the interop mount.
41
+ * They join the list so the **Prelaunch Windows Chrome** run drives what the
42
+ * picker picked rather than what it happens to locate first — and, offered
43
+ * without being probed, they answer a note and never a version (see the
44
+ * `blockedForPlatform` answer threaded through ./scan.ts).
45
+ */
46
+ export function chromeExecutableCandidates(entry, savedIds = [], effectivePath = "", extraCandidates = []) {
47
+ const rowPaths = Array.isArray(entry?.chromePaths) ? entry.chromePaths : [];
48
+ const saved = Array.isArray(savedIds) ? savedIds : [];
49
+ const extra = Array.isArray(extraCandidates) ? extraCandidates : [];
50
+ const seen = new Set();
51
+ const candidates = [];
52
+ const push = (value) => {
53
+ const path = String(value ?? "").trim();
54
+ if (path === "" || seen.has(path))
55
+ return;
56
+ seen.add(path);
57
+ candidates.push(path);
58
+ };
59
+ for (const path of rowPaths)
60
+ push(path);
61
+ for (const path of extra)
62
+ push(path);
63
+ for (const path of saved)
64
+ push(path);
65
+ push(effectivePath);
66
+ return candidates;
67
+ }
68
+ //# sourceMappingURL=candidates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"candidates.js","sourceRoot":"","sources":["../../../src/host/discovery/candidates.ts"],"names":[],"mappings":"AAcA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAChC,KAAK,EAAE;QACH,2BAA2B;QAC3B,wBAAwB;QACxB,+BAA+B;QAC/B,8BAA8B;QAC9B,eAAe;KAClB;IACD,MAAM,EAAE,CAAC,8DAA8D,CAAC;IACxE,KAAK,EAAE;QACH,4DAA4D;QAC5D,kEAAkE;KACrE;CACJ,CAAC;AAEF,gFAAgF;AAChF,MAAM,UAAU,kBAAkB,CAAC,WAA4B,OAAO,CAAC,QAAQ;IAC3E,MAAM,UAAU,GAAG,oBAAoB,CAAC,QAA6C,CAAC,CAAC;IACvF,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,0BAA0B,CACtC,KAA2C,EAC3C,WAA8B,EAAE,EAChC,aAAa,GAAG,EAAE,EAClB,kBAAqC,EAAE;IAEvC,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5E,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;IACpE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,CAAC,KAAc,EAAQ,EAAE;QAClC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACxC,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO;QAC1C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACf,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,QAAQ;QAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,aAAa,CAAC,CAAC;IACpB,OAAO,UAAU,CAAC;AACtB,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Host half — the Chrome executable: candidate locations, the `--version`
3
+ * probes, the executable **scan** that produces the card's dropdown options, and
4
+ * the check run that ties them together.
5
+ *
6
+ * ./candidates.ts the platform Chrome locations + the ordered candidate list
7
+ * ./probe.ts the `--version` probe + presence + identity helpers
8
+ * ./scan.ts the scan, the discover-the-first-runnable run, the check
9
+ *
10
+ * Upstream starts the browser LAZILY, on the first tool call, so the check runs
11
+ * probes eagerly instead of waiting for a tool call. There is no "auto" mode:
12
+ * the scan lists what exists, the card picks one, and what is picked stays
13
+ * picked — a path that later disappears is reported broken, never silently
14
+ * substituted. See ./scan.ts for the full behaviour and the WSL interop note.
15
+ */
16
+ export { chromeExecutableCandidates, DEFAULT_CHROME_PATHS, defaultChromePaths } from "./candidates.js";
17
+ export { probeExecutable, readWindowsInstallVersion } from "./probe.js";
18
+ export { checkChrome, discoverChrome, scanChromeExecutables } from "./scan.js";
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/host/discovery/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACvG,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Host half — the Chrome executable: candidate locations, the `--version`
3
+ * probes, the executable **scan** that produces the card's dropdown options, and
4
+ * the check run that ties them together.
5
+ *
6
+ * ./candidates.ts the platform Chrome locations + the ordered candidate list
7
+ * ./probe.ts the `--version` probe + presence + identity helpers
8
+ * ./scan.ts the scan, the discover-the-first-runnable run, the check
9
+ *
10
+ * Upstream starts the browser LAZILY, on the first tool call, so the check runs
11
+ * probes eagerly instead of waiting for a tool call. There is no "auto" mode:
12
+ * the scan lists what exists, the card picks one, and what is picked stays
13
+ * picked — a path that later disappears is reported broken, never silently
14
+ * substituted. See ./scan.ts for the full behaviour and the WSL interop note.
15
+ */
16
+ export { chromeExecutableCandidates, DEFAULT_CHROME_PATHS, defaultChromePaths } from "./candidates.js";
17
+ export { probeExecutable, readWindowsInstallVersion } from "./probe.js";
18
+ export { checkChrome, discoverChrome, scanChromeExecutables } from "./scan.js";
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/host/discovery/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACvG,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The version a Windows install states without being run: the highest
3
+ * `<major>.<minor>.<build>.<patch>` folder beside the executable (the layout
4
+ * Chrome, Edge, Brave and Chromium all install with), or
5
+ * {@link WINDOWS_VERSION_UNKNOWN} when none is there. A missing file rejects
6
+ * like the spawn would; a bare name (no folder to look in) answers unknown.
7
+ */
8
+ export declare function readWindowsInstallVersion(target: string): string;
9
+ /**
10
+ * Answer one executable's version. On Windows nothing is spawned — a Chromium
11
+ * browser asked `--version` there opens a window instead of answering — and
12
+ * the version is read off the install ({@link readWindowsInstallVersion}).
13
+ * Everywhere else: one `chromePath --version` probe (scrubbed parent env,
14
+ * bounded timeout). Resolves the first stdout line (the version); ENOENT
15
+ * rejects with "Chrome executable not found: <path>" carrying code "ENOENT"; a
16
+ * non-zero exit rejects with the first non-empty stderr/stdout line.
17
+ */
18
+ export declare function probeExecutable(target: string, platform?: NodeJS.Platform): Promise<string>;
19
+ /** True when a candidate path can be handed to the OS for a `--version` probe.
20
+ * A path that is absent (or not executable) never reaches the spawn: a
21
+ * Chrome-less host runs one scan without launching anything. Paths with no
22
+ * directory separator go straight to the spawn so the OS resolves them
23
+ * through `PATH`. */
24
+ export declare function presentOnDisk(candidate: string): boolean;
25
+ /** Identity key used to fold two spellings of the same binary (`google-chrome`
26
+ * resolving onto `/usr/bin/google-chrome`) into one option. Falls back to the
27
+ * path itself when `realpath` cannot resolve it. */
28
+ export declare function identity(candidate: string): string;
29
+ //# sourceMappingURL=probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../../src/host/discovery/probe.ts"],"names":[],"mappings":"AA6BA;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAyBhE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,OAAO,CAAC,MAAM,CAAC,CA+C7G;AAED;;;;qBAIqB;AACrB,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAWxD;AAED;;oDAEoD;AACpD,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMlD"}
@@ -0,0 +1,155 @@
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, readdirSync, realpathSync, statSync } from "node:fs";
14
+ import * as path from "node:path";
15
+ import { scrubbedParentEnv } from "@deepseek-ai/dsh-subprocess";
16
+ import { CHECK_TIMEOUT_MS, WINDOWS_VERSION_UNKNOWN } from "../constants.js";
17
+ import { firstLine } from "../status.js";
18
+ /** A Chromium install's version folder name: `155.0.8059.85`. */
19
+ const VERSION_FOLDER = /^\d+\.\d+\.\d+\.\d+$/u;
20
+ /** The "not found" rejection, carrying code "ENOENT" for the scan to drop. */
21
+ function missingExecutable(target) {
22
+ const missing = new Error(`Chrome executable not found: ${target}`);
23
+ Object.defineProperty(missing, "code", { value: "ENOENT", writable: true, enumerable: false, configurable: true });
24
+ return missing;
25
+ }
26
+ /**
27
+ * The version a Windows install states without being run: the highest
28
+ * `<major>.<minor>.<build>.<patch>` folder beside the executable (the layout
29
+ * Chrome, Edge, Brave and Chromium all install with), or
30
+ * {@link WINDOWS_VERSION_UNKNOWN} when none is there. A missing file rejects
31
+ * like the spawn would; a bare name (no folder to look in) answers unknown.
32
+ */
33
+ export function readWindowsInstallVersion(target) {
34
+ const win = path.win32;
35
+ if (!target.includes("/") && !target.includes("\\"))
36
+ return WINDOWS_VERSION_UNKNOWN;
37
+ let isFile = false;
38
+ try {
39
+ isFile = statSync(target).isFile();
40
+ }
41
+ catch {
42
+ // Absent — answered below like a spawn's ENOENT.
43
+ }
44
+ if (!isFile)
45
+ throw missingExecutable(target);
46
+ let names;
47
+ try {
48
+ names = readdirSync(win.dirname(target));
49
+ }
50
+ catch {
51
+ return WINDOWS_VERSION_UNKNOWN;
52
+ }
53
+ const versions = names.filter((name) => VERSION_FOLDER.test(name));
54
+ if (versions.length === 0)
55
+ return WINDOWS_VERSION_UNKNOWN;
56
+ const parts = (name) => name.split(".").map(Number);
57
+ versions.sort((a, b) => {
58
+ const [pa, pb] = [parts(a), parts(b)];
59
+ for (let i = 0; i < 4; i++)
60
+ if (pa[i] !== pb[i])
61
+ return pa[i] - pb[i];
62
+ return 0;
63
+ });
64
+ return versions[versions.length - 1];
65
+ }
66
+ /**
67
+ * Answer one executable's version. On Windows nothing is spawned — a Chromium
68
+ * browser asked `--version` there opens a window instead of answering — and
69
+ * the version is read off the install ({@link readWindowsInstallVersion}).
70
+ * Everywhere else: one `chromePath --version` probe (scrubbed parent env,
71
+ * bounded timeout). Resolves the first stdout line (the version); ENOENT
72
+ * rejects with "Chrome executable not found: <path>" carrying code "ENOENT"; a
73
+ * non-zero exit rejects with the first non-empty stderr/stdout line.
74
+ */
75
+ export function probeExecutable(target, platform = process.platform) {
76
+ if (platform === "win32") {
77
+ try {
78
+ return Promise.resolve(readWindowsInstallVersion(target));
79
+ }
80
+ catch (error) {
81
+ return Promise.reject(error);
82
+ }
83
+ }
84
+ return new Promise((resolve, reject) => {
85
+ let child;
86
+ try {
87
+ child = spawn(target, ["--version"], {
88
+ env: scrubbedParentEnv(),
89
+ stdio: ["ignore", "pipe", "pipe"],
90
+ timeout: CHECK_TIMEOUT_MS,
91
+ killSignal: "SIGKILL"
92
+ });
93
+ }
94
+ catch (error) {
95
+ reject(new Error(`could not run "${target} --version": ${String(error)}`));
96
+ return;
97
+ }
98
+ let stdout = "";
99
+ let stderr = "";
100
+ child.stdout?.on("data", (chunk) => (stdout += chunk));
101
+ child.stderr?.on("data", (chunk) => (stderr += chunk));
102
+ child.on("error", (error) => {
103
+ const code = error && typeof error.code === "string" ? error.code : "";
104
+ if (code === "ENOENT") {
105
+ reject(missingExecutable(target));
106
+ return;
107
+ }
108
+ reject(new Error(`could not run "${target} --version": ${String(error)}`));
109
+ });
110
+ child.on("close", (code) => {
111
+ if (code === null) {
112
+ reject(new Error(`"${target} --version" timed out after ${String(CHECK_TIMEOUT_MS)}ms`));
113
+ return;
114
+ }
115
+ if (code !== 0) {
116
+ const detail = firstLine(stderr) !== "" ? firstLine(stderr) : firstLine(stdout) !== "" ? firstLine(stdout) : `exit code ${String(code)}`;
117
+ reject(new Error(`"${target} --version" failed: ${detail}`));
118
+ return;
119
+ }
120
+ resolve(firstLine(stdout));
121
+ });
122
+ });
123
+ }
124
+ /** True when a candidate path can be handed to the OS for a `--version` probe.
125
+ * A path that is absent (or not executable) never reaches the spawn: a
126
+ * Chrome-less host runs one scan without launching anything. Paths with no
127
+ * directory separator go straight to the spawn so the OS resolves them
128
+ * through `PATH`. */
129
+ export function presentOnDisk(candidate) {
130
+ if (!candidate.includes("/") && !candidate.includes("\\"))
131
+ return true;
132
+ try {
133
+ // A directory (or a socket, or a fifo) is not an executable, and
134
+ // spawning one to find out is a side effect we do not want.
135
+ if (!statSync(candidate).isFile())
136
+ return false;
137
+ accessSync(candidate, constants.X_OK);
138
+ return true;
139
+ }
140
+ catch {
141
+ return false;
142
+ }
143
+ }
144
+ /** Identity key used to fold two spellings of the same binary (`google-chrome`
145
+ * resolving onto `/usr/bin/google-chrome`) into one option. Falls back to the
146
+ * path itself when `realpath` cannot resolve it. */
147
+ export function identity(candidate) {
148
+ try {
149
+ return realpathSync(candidate);
150
+ }
151
+ catch {
152
+ return candidate;
153
+ }
154
+ }
155
+ //# 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,72 @@
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 as a `note`, never as a failure (the one case
15
+ * is a Windows `chrome.exe` on a WSL host, whose probe would start a browser
16
+ * instance it can never drive — 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 leave the check mute: they declare a connect mode
48
+ * (`--browserUrl` / `--browser-url` / `-u`, `--wsEndpoint` /
49
+ * `--ws-endpoint` / `-w`, `--autoConnect` / `--auto-connect`), name a
50
+ * config file (`--config`), or fix another `--channel` than the `stable`
51
+ * the candidate list models → resolve "": there is no local executable
52
+ * this check could honestly answer for.
53
+ * - `blockedForPlatform` answers non-empty for what is selected → resolve "" with
54
+ * **no spawn**. A Windows `chrome.exe` on a WSL host is the case: its
55
+ * `--version` probe answers (which is why the selection looks healthy) but
56
+ * answering means attaching to the Windows browser session, and that *starts*
57
+ * a browser instance no tool call could drive
58
+ * ({@link WSL_WINDOWS_LAUNCH_ERROR}).
59
+ *
60
+ * A run that probes **nothing** (no candidates, a connect mode, a config file
61
+ * or another channel standing in for the local executable, or a blocked path)
62
+ * resolves "" — callers must treat that as "no evidence", never as health.
63
+ *
64
+ * @param entry - validated {@link ChromeMcpConfig}.
65
+ * @param extraFlags - the flags list the bridge currently launches with;
66
+ * inspected for the entries that leave the check mute.
67
+ * @param blockedForPlatform - answers a reason for a path this host must never
68
+ * exec, `""` for one it may probe.
69
+ * @returns the executable version line, or "" when nothing is probed.
70
+ */
71
+ export declare function checkChrome(entry: ChromeMcpConfig, extraFlags?: string[], blockedForPlatform?: (candidate: string) => string): Promise<string>;
72
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/host/discovery/scan.ts"],"names":[],"mappings":"AA8BA,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,CAmDnC;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAChC,cAAc,EAAE,MAAM,EAAE,EACxB,kBAAkB,GAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAiB,GAC7D,OAAO,CAAC,MAAM,CAAC,CAoBjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;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,CAUjB"}