@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.
Files changed (171) hide show
  1. package/README.md +22 -78
  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 +1433 -568
  6. package/lib/client.js.map +7 -0
  7. package/lib/host/apply.d.ts +3 -0
  8. package/lib/host/apply.d.ts.map +1 -0
  9. package/lib/host/apply.js +31 -0
  10. package/lib/host/apply.js.map +1 -0
  11. package/lib/host/bridge.d.ts +65 -0
  12. package/lib/host/bridge.d.ts.map +1 -0
  13. package/lib/host/bridge.js +176 -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/constants.d.ts +229 -0
  20. package/lib/host/constants.d.ts.map +1 -0
  21. package/lib/host/constants.js +242 -0
  22. package/lib/host/constants.js.map +1 -0
  23. package/lib/host/controller/bridge-run.d.ts +38 -0
  24. package/lib/host/controller/bridge-run.d.ts.map +1 -0
  25. package/lib/host/controller/bridge-run.js +69 -0
  26. package/lib/host/controller/bridge-run.js.map +1 -0
  27. package/lib/host/controller/captures.d.ts +22 -0
  28. package/lib/host/controller/captures.d.ts.map +1 -0
  29. package/lib/host/controller/captures.js +60 -0
  30. package/lib/host/controller/captures.js.map +1 -0
  31. package/lib/host/controller/commits.d.ts +4 -0
  32. package/lib/host/controller/commits.d.ts.map +1 -0
  33. package/lib/host/controller/commits.js +75 -0
  34. package/lib/host/controller/commits.js.map +1 -0
  35. package/lib/host/controller/controller.d.ts +40 -0
  36. package/lib/host/controller/controller.d.ts.map +1 -0
  37. package/lib/host/controller/controller.js +167 -0
  38. package/lib/host/controller/controller.js.map +1 -0
  39. package/lib/host/controller/index.d.ts +26 -0
  40. package/lib/host/controller/index.d.ts.map +1 -0
  41. package/lib/host/controller/index.js +25 -0
  42. package/lib/host/controller/index.js.map +1 -0
  43. package/lib/host/controller/notes.d.ts +26 -0
  44. package/lib/host/controller/notes.d.ts.map +1 -0
  45. package/lib/host/controller/notes.js +49 -0
  46. package/lib/host/controller/notes.js.map +1 -0
  47. package/lib/host/controller/persist.d.ts +9 -0
  48. package/lib/host/controller/persist.d.ts.map +1 -0
  49. package/lib/host/controller/persist.js +51 -0
  50. package/lib/host/controller/persist.js.map +1 -0
  51. package/lib/host/controller/runs.d.ts +56 -0
  52. package/lib/host/controller/runs.d.ts.map +1 -0
  53. package/lib/host/controller/runs.js +211 -0
  54. package/lib/host/controller/runs.js.map +1 -0
  55. package/lib/host/controller/state.d.ts +70 -0
  56. package/lib/host/controller/state.d.ts.map +1 -0
  57. package/lib/host/controller/state.js +2 -0
  58. package/lib/host/controller/state.js.map +1 -0
  59. package/lib/host/controller/windows-run.d.ts +9 -0
  60. package/lib/host/controller/windows-run.d.ts.map +1 -0
  61. package/lib/host/controller/windows-run.js +78 -0
  62. package/lib/host/controller/windows-run.js.map +1 -0
  63. package/lib/host/discovery/candidates.d.ts +37 -0
  64. package/lib/host/discovery/candidates.d.ts.map +1 -0
  65. package/lib/host/discovery/candidates.js +56 -0
  66. package/lib/host/discovery/candidates.js.map +1 -0
  67. package/lib/host/discovery/index.d.ts +18 -0
  68. package/lib/host/discovery/index.d.ts.map +1 -0
  69. package/lib/host/discovery/index.js +18 -0
  70. package/lib/host/discovery/index.js.map +1 -0
  71. package/lib/host/discovery/probe.d.ts +18 -0
  72. package/lib/host/discovery/probe.d.ts.map +1 -0
  73. package/lib/host/discovery/probe.js +97 -0
  74. package/lib/host/discovery/probe.js.map +1 -0
  75. package/lib/host/discovery/scan.d.ts +67 -0
  76. package/lib/host/discovery/scan.d.ts.map +1 -0
  77. package/lib/host/discovery/scan.js +169 -0
  78. package/lib/host/discovery/scan.js.map +1 -0
  79. package/lib/host/flags.d.ts +42 -0
  80. package/lib/host/flags.d.ts.map +1 -0
  81. package/lib/host/flags.js +118 -0
  82. package/lib/host/flags.js.map +1 -0
  83. package/lib/host/platform.d.ts +38 -0
  84. package/lib/host/platform.d.ts.map +1 -0
  85. package/lib/host/platform.js +64 -0
  86. package/lib/host/platform.js.map +1 -0
  87. package/lib/host/plugin-meta.d.ts +12 -0
  88. package/lib/host/plugin-meta.d.ts.map +1 -0
  89. package/lib/host/plugin-meta.js +12 -0
  90. package/lib/host/plugin-meta.js.map +1 -0
  91. package/lib/host/schema.d.ts +307 -0
  92. package/lib/host/schema.d.ts.map +1 -0
  93. package/lib/host/schema.js +171 -0
  94. package/lib/host/schema.js.map +1 -0
  95. package/lib/host/settings.d.ts +9 -0
  96. package/lib/host/settings.d.ts.map +1 -0
  97. package/lib/host/settings.js +70 -0
  98. package/lib/host/settings.js.map +1 -0
  99. package/lib/host/status.d.ts +28 -0
  100. package/lib/host/status.d.ts.map +1 -0
  101. package/lib/host/status.js +60 -0
  102. package/lib/host/status.js.map +1 -0
  103. package/lib/host/tool.d.ts +59 -0
  104. package/lib/host/tool.d.ts.map +1 -0
  105. package/lib/host/tool.js +51 -0
  106. package/lib/host/tool.js.map +1 -0
  107. package/lib/host/types/config.d.ts +47 -0
  108. package/lib/host/types/config.d.ts.map +1 -0
  109. package/lib/host/types/config.js +2 -0
  110. package/lib/host/types/config.js.map +1 -0
  111. package/lib/host/types/executable.d.ts +30 -0
  112. package/lib/host/types/executable.d.ts.map +1 -0
  113. package/lib/host/types/executable.js +9 -0
  114. package/lib/host/types/executable.js.map +1 -0
  115. package/lib/host/types/index.d.ts +23 -0
  116. package/lib/host/types/index.d.ts.map +1 -0
  117. package/lib/host/types/index.js +2 -0
  118. package/lib/host/types/index.js.map +1 -0
  119. package/lib/host/types/plugin.d.ts +38 -0
  120. package/lib/host/types/plugin.d.ts.map +1 -0
  121. package/lib/host/types/plugin.js +10 -0
  122. package/lib/host/types/plugin.js.map +1 -0
  123. package/lib/host/types/settings.d.ts +127 -0
  124. package/lib/host/types/settings.d.ts.map +1 -0
  125. package/lib/host/types/settings.js +2 -0
  126. package/lib/host/types/settings.js.map +1 -0
  127. package/lib/host/types/stderr.d.ts +53 -0
  128. package/lib/host/types/stderr.d.ts.map +1 -0
  129. package/lib/host/types/stderr.js +9 -0
  130. package/lib/host/types/stderr.js.map +1 -0
  131. package/lib/host/types/windows.d.ts +39 -0
  132. package/lib/host/types/windows.d.ts.map +1 -0
  133. package/lib/host/types/windows.js +9 -0
  134. package/lib/host/types/windows.js.map +1 -0
  135. package/lib/host/values.d.ts +89 -0
  136. package/lib/host/values.d.ts.map +1 -0
  137. package/lib/host/values.js +212 -0
  138. package/lib/host/values.js.map +1 -0
  139. package/lib/host/windows/connect-flags.d.ts +16 -0
  140. package/lib/host/windows/connect-flags.d.ts.map +1 -0
  141. package/lib/host/windows/connect-flags.js +67 -0
  142. package/lib/host/windows/connect-flags.js.map +1 -0
  143. package/lib/host/windows/index.d.ts +31 -0
  144. package/lib/host/windows/index.d.ts.map +1 -0
  145. package/lib/host/windows/index.js +30 -0
  146. package/lib/host/windows/index.js.map +1 -0
  147. package/lib/host/windows/landing.d.ts +47 -0
  148. package/lib/host/windows/landing.d.ts.map +1 -0
  149. package/lib/host/windows/landing.js +174 -0
  150. package/lib/host/windows/landing.js.map +1 -0
  151. package/lib/host/windows/link.d.ts +11 -0
  152. package/lib/host/windows/link.d.ts.map +1 -0
  153. package/lib/host/windows/link.js +52 -0
  154. package/lib/host/windows/link.js.map +1 -0
  155. package/lib/host/windows/paths.d.ts +43 -0
  156. package/lib/host/windows/paths.d.ts.map +1 -0
  157. package/lib/host/windows/paths.js +121 -0
  158. package/lib/host/windows/paths.js.map +1 -0
  159. package/lib/host/windows/run.d.ts +74 -0
  160. package/lib/host/windows/run.d.ts.map +1 -0
  161. package/lib/host/windows/run.js +210 -0
  162. package/lib/host/windows/run.js.map +1 -0
  163. package/lib/host/windows/spawn.d.ts +22 -0
  164. package/lib/host/windows/spawn.d.ts.map +1 -0
  165. package/lib/host/windows/spawn.js +73 -0
  166. package/lib/host/windows/spawn.js.map +1 -0
  167. package/lib/index.d.ts +86 -0
  168. package/lib/index.d.ts.map +1 -0
  169. package/lib/index.js +72 -625
  170. package/lib/index.js.map +1 -0
  171. package/package.json +26 -4
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Controller — the executable run, its serialization, and the Windows trigger.
3
+ *
4
+ * Every executable action goes through one **run**: probe the candidate list the
5
+ * saved rows + row config + selection carry, publish the per-path answers, and
6
+ * merge what was found back into the saved rows (keeping the names the user
7
+ * gave them). When nothing is configured at all, the first runnable entry is
8
+ * seeded. A `probe` is the follow-up probe of the selection that answers the
9
+ * version line the card shows; the Windows Chrome run shares this same
10
+ * one-run-at-a-time chain.
11
+ */
12
+ import { bridgeConfig } from "../bridge.js";
13
+ import { entryIds, mergeEntries, normalizeEntries } from "../catalog.js";
14
+ import { checkChrome, chromeExecutableCandidates, scanChromeExecutables } from "../discovery/index.js";
15
+ import { flagsSkipCheck } from "../flags.js";
16
+ import { firstLine, isChromeMissing } from "../status.js";
17
+ import { windowsChromeUrl } from "../windows/index.js";
18
+ import { readPersistedCustomPaths } from "../values.js";
19
+ import { configForBridge, restartBridge } from "./bridge-run.js";
20
+ import { noteSelection, noteStderr } from "./notes.js";
21
+ import { persistChromePath, persistExecutables } from "./persist.js";
22
+ import { runWindowsChrome } from "./windows-run.js";
23
+ /** Element-wise equality of two saved-row lists (order is the dropdown order). */
24
+ export function sameEntries(a, b) {
25
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)
26
+ return false;
27
+ return a.every((entry, index) => entry.id === b[index].id && entry.name === b[index].name);
28
+ }
29
+ /**
30
+ * Fold the legacy hand-typed MRU into the rows, exactly once. It is the same list
31
+ * the older card used to write, so reading it never duplicates a row the card
32
+ * already saved: the merge keeps stored rows and only appends ids that are
33
+ * missing, and the result lands in the persisted rows instead of staying
34
+ * readable forever as a second source.
35
+ */
36
+ export function mergeLegacyPaths(controller) {
37
+ const { state } = controller;
38
+ if (state.legacyPathsMerged)
39
+ return state.runningExecutables;
40
+ state.legacyPathsMerged = true;
41
+ const legacy = readPersistedCustomPaths(controller.ctx);
42
+ if (legacy.length === 0)
43
+ return state.runningExecutables;
44
+ const merged = mergeEntries(state.runningExecutables, legacy);
45
+ if (merged.changed) {
46
+ state.runningExecutables = merged.entries;
47
+ void persistExecutables(controller, merged.entries);
48
+ controller.ctx.logger.info(`chrome-devtools-mcp(${controller.config.serverName}): folded ${String(legacy.length)} saved path(s) from the legacy chromeCustomPaths list into the executable rows`);
49
+ }
50
+ return state.runningExecutables;
51
+ }
52
+ /**
53
+ * One executable run. Probe every candidate the row config and the saved rows
54
+ * carry (plus the selection — the same path may appear as a row), publish what
55
+ * answered as per-path status, and merge what was found into the saved rows,
56
+ * keeping the names their user gave them. When nothing is configured at all
57
+ * (neither layer carries a path) the first runnable entry is **seeded**: written
58
+ * into the persisted `chromePath` once, so what the picker shows is what the
59
+ * bridge runs. A selection that is already fixed is never re-resolved, however
60
+ * broken.
61
+ * @returns the per-path statuses the run answered with.
62
+ */
63
+ export async function runExecutableDiscovery(controller) {
64
+ const { state } = controller;
65
+ const live = state.source();
66
+ // Rows are user-authored; re-normalize on every read (the client writes them
67
+ // in one shot, so the shape it hands may be anything).
68
+ const stored = normalizeEntries(live.executables);
69
+ const storedChanged = !sameEntries(stored, state.runningExecutables);
70
+ state.runningExecutables = storedChanged ? stored : mergeLegacyPaths(controller);
71
+ const savedIds = entryIds(state.runningExecutables);
72
+ const candidates = chromeExecutableCandidates(controller.config, savedIds, state.runningChromePath);
73
+ let statuses = [];
74
+ try {
75
+ statuses = await scanChromeExecutables(candidates, controller.blockedForPlatform);
76
+ }
77
+ catch (error) {
78
+ controller.ctx.logger.warn(`chrome-devtools-mcp(${controller.config.serverName}): executable run failed: ${String(error)}`);
79
+ }
80
+ state.entry.executableStatus = statuses;
81
+ // A found path that is not a row yet becomes one, nameless; a row the user
82
+ // named keeps that name. A path that vanished is dropped by the scan and so
83
+ // stops being offered — the reference's "Fetch executables" rule.
84
+ const merged = mergeEntries(state.runningExecutables, statuses.map((status) => status.path));
85
+ if (merged.changed) {
86
+ state.runningExecutables = merged.entries;
87
+ void persistExecutables(controller, merged.entries);
88
+ }
89
+ if (state.runningChromePath === "") {
90
+ const seeded = statuses.find((status) => status.version !== "" && status.error === "");
91
+ if (seeded !== void 0 && !flagsSkipCheck(state.runningFlags)) {
92
+ // Seeding is a selection change like any other: the bridge has to
93
+ // restart carrying it, otherwise the card would claim a path the
94
+ // running argv does not carry.
95
+ controller.ctx.logger.info(`chrome-devtools-mcp(${controller.config.serverName}): no executable configured — seeding chromePath = ${seeded.path} (found by scan)`);
96
+ state.seededPath = seeded.path;
97
+ void persistChromePath(controller, seeded.path);
98
+ // Already inside this run: the status list above already carries the
99
+ // seeded path's own answer, so no follow-up run.
100
+ applyChromePath(controller, seeded.path, "selected", false);
101
+ }
102
+ else if (candidates.length > 0 && !flagsSkipCheck(state.runningFlags) && statuses.every((status) => status.error !== "" || status.version === "")) {
103
+ // Nothing present at all: the known executable-missing state.
104
+ state.entry.lastError = firstLine(`Chrome executable not found: no executable detected (checked: ${candidates.join(", ")})`);
105
+ state.entry.chromeMissing = isChromeMissing(state.entry.lastError);
106
+ }
107
+ }
108
+ noteSelection(controller);
109
+ return statuses;
110
+ }
111
+ /**
112
+ * The probe of the *selection* — the one run that answers the version line the
113
+ * card shows under the pill. Nothing probed (no selection, or a connect-mode
114
+ * flag) must not clear anything: upstream starts the browser lazily, so silence
115
+ * is not health.
116
+ */
117
+ export async function probeSelection(controller) {
118
+ const { state } = controller;
119
+ // Connect mode launches nothing locally, so there is no local executable to
120
+ // answer for: the card mutes the pill and shows no version line for a probe
121
+ // the host cannot run.
122
+ if (flagsSkipCheck(state.runningFlags)) {
123
+ state.entry.chromeVersion = "";
124
+ return "";
125
+ }
126
+ if (state.runningChromePath === "") {
127
+ state.entry.chromeVersion = "";
128
+ return "";
129
+ }
130
+ try {
131
+ const version = await checkChrome({ ...controller.config, extraFlags: state.runningFlags, chromePath: state.runningChromePath }, state.runningFlags, controller.blockedForPlatform);
132
+ state.entry.chromeVersion = version;
133
+ if (version !== "") {
134
+ state.entry.lastError = "";
135
+ state.entry.chromeMissing = false;
136
+ }
137
+ return version;
138
+ }
139
+ catch (error) {
140
+ state.entry.lastError = firstLine(error instanceof Error ? error.message : String(error));
141
+ // A failed probe says nothing about the version: keep no stale answer
142
+ // behind the error.
143
+ state.entry.chromeVersion = "";
144
+ state.entry.chromeMissing = isChromeMissing(state.entry.lastError);
145
+ controller.ctx.logger.warn(`chrome-devtools-mcp(${controller.config.serverName}): executable probe failed: ${state.entry.lastError}`);
146
+ return "";
147
+ }
148
+ }
149
+ /**
150
+ * Restart the bridge connection with a different executable selected — the argv
151
+ * tail carries `--executablePath=<path>`, so unlike a flag change this one is
152
+ * what the card's pill claims is running. `rerun` schedules the scan+probe that
153
+ * follows a selection change; a caller that is already inside that run (the
154
+ * seeding branch above) passes `false`.
155
+ */
156
+ export function applyChromePath(controller, path, nextSource, rerun = true) {
157
+ const { state } = controller;
158
+ state.runningChromePath = path;
159
+ state.runningChromeSource = nextSource;
160
+ noteSelection(controller);
161
+ controller.ctx.logger.info(`chrome-devtools-mcp(${controller.config.serverName}): executable → "${path || "(none)"}" (restarting the bridge connection)`);
162
+ const built = bridgeConfig(configForBridge(controller, state.runningFlags), state.runningFlags, state.runningStderrMode);
163
+ noteStderr(controller, built);
164
+ restartBridge(controller, built, "executable update failed");
165
+ // A different executable reads a different machine: refresh the list and
166
+ // probe what is now selected, so the pill's version is the new one's.
167
+ if (rerun)
168
+ queue(controller, "probe");
169
+ }
170
+ /**
171
+ * Serialize one unit of work: a rows-only refresh, a run that also re-probes
172
+ * what is selected, or the Windows Chrome launch. Windows runs share this chain
173
+ * because the invariant is "one run at a time" — nothing about it interacts with
174
+ * the local probe.
175
+ */
176
+ export function queue(controller, kind) {
177
+ const { state } = controller;
178
+ state.runs = state.runs
179
+ .then(async () => {
180
+ if (kind === "windows") {
181
+ await runWindowsChrome(controller);
182
+ }
183
+ else {
184
+ await runExecutableDiscovery(controller);
185
+ if (kind === "probe")
186
+ await probeSelection(controller);
187
+ }
188
+ state.entry.executableDiscoveryRevision += 1;
189
+ })
190
+ .catch(() => { });
191
+ return state.runs;
192
+ }
193
+ /**
194
+ * One Windows Chrome run on demand: queued on the same chain as the button (one
195
+ * run at a time), resolved once it settled. The answer is the base-layer mirror
196
+ * read after the run — the tool surface says what `windowsChromeStatus` says,
197
+ * never more than the run answered.
198
+ */
199
+ export async function prelaunchWindowsChrome(controller) {
200
+ const { state } = controller;
201
+ await queue(controller, "windows");
202
+ const status = state.entry.windowsChromeStatus;
203
+ if (status.state === "connected" && status.port > 0) {
204
+ return `Windows Chrome connected at ${windowsChromeUrl(status.port)} — the bridge connects to it instead of launching one.`;
205
+ }
206
+ if (status.state === "not-applicable") {
207
+ return "This host is not a WSL instance: there is no Windows-side browser here to drive.";
208
+ }
209
+ return `Windows Chrome did not connect (${status.state}): ${status.error}`;
210
+ }
211
+ //# sourceMappingURL=runs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs.js","sourceRoot":"","sources":["../../../src/host/controller/runs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Controller internals — the live state + the context every controller method
3
+ * reads.
4
+ *
5
+ * The public half (`createChromeMcpController`, `ChromeMcpController`,
6
+ * `ChromeMcpControllerDeps`) lives in ./controller.ts; the behavior it wires
7
+ * together is split across the sibling modules here (`notes`, `bridge-run`,
8
+ * `runs`, `windows-run`, `persist`, `captures`, `commits`). This file names the
9
+ * state those helpers share — every base-layer mutation targets `state.entry`,
10
+ * every run reads its source through `state.source`, and the immutable context
11
+ * pieces a method needs to act on (the row config, the WSL answer, the injected
12
+ * Windows run) sit alongside it. Nothing here is part of the public surface.
13
+ */
14
+ import type { BridgeStderrMode, ChromeMcpConfig, ChromeExecutableEntry, EffectiveChromeSource, McpBridge, PluginContext, SettingsResolved, WindowsChromeRun } from "../types/index.js";
15
+ import type { WindowsChromeRunOptions } from "../windows/index.js";
16
+ /** The live state one controller instance owns and mutates. */
17
+ export interface ControllerState {
18
+ /** The composition base layer served alongside the user layer. */
19
+ entry: SettingsResolved;
20
+ /** The live resolved settings source (swapped by the installSection hook). */
21
+ source: () => SettingsResolved;
22
+ /** Flags the nested bridge currently launches with. */
23
+ runningFlags: string[];
24
+ /** Effective bridge stderr mode ("log"/"console"). */
25
+ runningStderrMode: BridgeStderrMode;
26
+ /** Executable the bridge actually launches with. */
27
+ runningChromePath: string;
28
+ /** Where that executable came from. */
29
+ runningChromeSource: EffectiveChromeSource;
30
+ /** The saved rows the last commit served, already normalized. */
31
+ runningExecutables: ChromeExecutableEntry[];
32
+ /** Last emitted stderr notice key (keeps the announce silent across churn). */
33
+ stderrNotice: string;
34
+ /** Last observed `refreshExecutablesNonce` (undefined until first commit). */
35
+ lastRefreshNonce: number | undefined;
36
+ /** Last observed `openWindowsChromeNonce` (undefined until first commit). */
37
+ lastWindowsNonce: number | undefined;
38
+ /** The executable this host seeded on the first run ("" = nothing). */
39
+ seededPath: string;
40
+ /** Whether the user layer has ever carried a path. */
41
+ seenUserSelection: boolean;
42
+ /** Serializes runs so rapid actions never interleave. */
43
+ runs: Promise<unknown>;
44
+ /** Whether the WSL + Windows-executable warning has been logged already. */
45
+ wslNoticeShown: boolean;
46
+ /** Whether the workspace `.chrome` view "kept" notice has been logged. */
47
+ profileLinkKeptShown: boolean;
48
+ /** Whether the legacy hand-typed MRU has been folded into the rows already. */
49
+ legacyPathsMerged: boolean;
50
+ }
51
+ /** Everything a controller method needs: the immutable context + the state. */
52
+ export interface Controller {
53
+ ctx: PluginContext;
54
+ config: ChromeMcpConfig;
55
+ /** True on a WSL host (where the Windows run is the only working path). */
56
+ wslHost: boolean;
57
+ /** A path this host must never exec (a Windows binary under WSL). */
58
+ blockedForPlatform: (candidate: string) => string;
59
+ /** The row-config executable source ("" = unset). */
60
+ rowChromePath: string;
61
+ /** The row-config extra flags, executable-path flag folded out. */
62
+ rowFlags: string[];
63
+ /** The Windows run half — injected by tests, the real one otherwise. */
64
+ windowsChrome: (options: WindowsChromeRunOptions) => Promise<WindowsChromeRun>;
65
+ /** The nested bridge fiber, driven by every flag/executable/stderr switch. */
66
+ bridge: McpBridge;
67
+ /** The live mutable state. */
68
+ state: ControllerState;
69
+ }
70
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/host/controller/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EACR,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,qBAAqB,EACrB,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAEnE,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC5B,kEAAkE;IAClE,KAAK,EAAE,gBAAgB,CAAC;IACxB,8EAA8E;IAC9E,MAAM,EAAE,MAAM,gBAAgB,CAAC;IAC/B,uDAAuD;IACvD,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,sDAAsD;IACtD,iBAAiB,EAAE,gBAAgB,CAAC;IACpC,oDAAoD;IACpD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uCAAuC;IACvC,mBAAmB,EAAE,qBAAqB,CAAC;IAC3C,iEAAiE;IACjE,kBAAkB,EAAE,qBAAqB,EAAE,CAAC;IAC5C,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,6EAA6E;IAC7E,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,iBAAiB,EAAE,OAAO,CAAC;IAC3B,yDAAyD;IACzD,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACvB,4EAA4E;IAC5E,cAAc,EAAE,OAAO,CAAC;IACxB,0EAA0E;IAC1E,oBAAoB,EAAE,OAAO,CAAC;IAC9B,+EAA+E;IAC/E,iBAAiB,EAAE,OAAO,CAAC;CAC9B;AAED,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACvB,GAAG,EAAE,aAAa,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;IACxB,2EAA2E;IAC3E,OAAO,EAAE,OAAO,CAAC;IACjB,qEAAqE;IACrE,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,qDAAqD;IACrD,aAAa,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,wEAAwE;IACxE,aAAa,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC/E,8EAA8E;IAC9E,MAAM,EAAE,SAAS,CAAC;IAClB,8BAA8B;IAC9B,KAAK,EAAE,eAAe,CAAC;CAC1B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/host/controller/state.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ import type { Controller } from "./state.js";
2
+ /**
3
+ * One **Prelaunch Windows Chrome** run. When the host is not WSL there is simply
4
+ * nothing to drive and the answer is `not-applicable`; otherwise the state moves
5
+ * through `launching` while the run (locate, prereq, launch, port) settles, and
6
+ * a connect that lands writes the flag through the ordinary bridge path.
7
+ */
8
+ export declare function runWindowsChrome(controller: Controller): Promise<void>;
9
+ //# sourceMappingURL=windows-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-run.d.ts","sourceRoot":"","sources":["../../../src/host/controller/windows-run.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAwD5E"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Controller — the one Windows Chrome run.
3
+ *
4
+ * The whole Windows path the card's **Prelaunch Windows Chrome** button drives,
5
+ * sequenced here against the injected run half (./run.ts in ../windows). Success
6
+ * ends with the connect entry written into the *saved* flags (replace-by-key, so
7
+ * what the bridge launches with afterwards is exactly what the card claims), and
8
+ * the run never kills what it started. Everything it answers lands in the base
9
+ * layer's `windowsChromeStatus`; the answer is read back off that mirror, never
10
+ * off the promise.
11
+ */
12
+ import { sameFlags } from "../flags.js";
13
+ import { firstLine } from "../status.js";
14
+ import { windowsChromeProjectDir, withBrowserUrlFlag } from "../windows/index.js";
15
+ import { applyFlags } from "./bridge-run.js";
16
+ import { persistExtraFlags } from "./persist.js";
17
+ /**
18
+ * One **Prelaunch Windows Chrome** run. When the host is not WSL there is simply
19
+ * nothing to drive and the answer is `not-applicable`; otherwise the state moves
20
+ * through `launching` while the run (locate, prereq, launch, port) settles, and
21
+ * a connect that lands writes the flag through the ordinary bridge path.
22
+ */
23
+ export async function runWindowsChrome(controller) {
24
+ const { state } = controller;
25
+ if (!controller.wslHost) {
26
+ state.entry.windowsChromeStatus = { state: "not-applicable", port: 0, error: "" };
27
+ return;
28
+ }
29
+ state.entry.windowsChromeStatus = { state: "launching", port: state.entry.windowsChromeStatus.port, error: "" };
30
+ const live = state.source();
31
+ const currentFlags = Array.isArray(live.extraFlags) ? live.extraFlags : state.runningFlags;
32
+ let result;
33
+ // The workspace that carries the run's `.chrome` view: the row-config `cwd`,
34
+ // else the live session's workspace — the run answers the GUI the user is
35
+ // driving, not the directory `dsh web` happened to be launched from (a view
36
+ // rooted at `~` links `~/.chrome`) — else the host's own cwd.
37
+ const projectDir = windowsChromeProjectDir(controller.config.cwd, controller.ctx.get("sessions"), process.cwd());
38
+ try {
39
+ result = await controller.windowsChrome({
40
+ cwd: projectDir,
41
+ currentFlags
42
+ });
43
+ }
44
+ catch (error) {
45
+ result = { state: "launch-failed", port: 0, url: "", profileDir: "", error: firstLine(error instanceof Error ? error.message : String(error)) };
46
+ }
47
+ state.entry.windowsChromeStatus = { state: result.state, port: result.port, error: firstLine(result.error) };
48
+ if (result.state === "connected" && result.url !== "") {
49
+ if (result.profileDir !== "") {
50
+ if (result.profileLink === "kept") {
51
+ // A real `.chrome` directory already sits at the view's spot:
52
+ // kept untouched, the link never clobbers what is already there
53
+ // — say it once, not on every run.
54
+ if (!state.profileLinkKeptShown) {
55
+ state.profileLinkKeptShown = true;
56
+ controller.ctx.logger.warn(`chrome-devtools-mcp(${controller.config.serverName}): ${projectDir}/.chrome is an existing directory — the Windows profile stays at ${result.profileDir}, not linked into the checkout`);
57
+ }
58
+ }
59
+ else {
60
+ controller.ctx.logger.info(`chrome-devtools-mcp(${controller.config.serverName}): Windows Chrome profile ${result.profileDir}, workspace view ${projectDir}/.chrome`);
61
+ }
62
+ }
63
+ const next = withBrowserUrlFlag(currentFlags, result.url);
64
+ state.entry.lastError = "";
65
+ if (!sameFlags(next, state.runningFlags)) {
66
+ // The bridge now connects instead of launching — the same flag path
67
+ // the extra-flags editor writes through. Persisting is what keeps
68
+ // connect mode across a reconnect and the next dsh start.
69
+ controller.ctx.logger.info(`chrome-devtools-mcp(${controller.config.serverName}): Windows Chrome connected at ${result.url} — switching the bridge to connect mode`);
70
+ applyFlags(controller, next);
71
+ void persistExtraFlags(controller, next);
72
+ }
73
+ return;
74
+ }
75
+ state.entry.lastError = firstLine(result.error);
76
+ controller.ctx.logger.warn(`chrome-devtools-mcp(${controller.config.serverName}): Windows Chrome run did not connect: ${state.entry.lastError}`);
77
+ }
78
+ //# 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,37 @@
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, WSL Windows-side `/mnt/c/…`
6
+ * deliberately absent) and the ordered candidate list one run folds together —
7
+ * row-config `chromePaths`, then the saved rows' ids, then the selection. The
8
+ * probes over that list live in ./scan.ts; the `--version` probe itself in
9
+ * ./probe.ts.
10
+ */
11
+ import type { ChromeMcpConfig } from "../types/index.js";
12
+ /**
13
+ * Google Chrome stable-channel locations probed by discovery when
14
+ * `chromePath` is empty — mirrors the upstream (puppeteer) system-channel
15
+ * resolution. WSL Windows-side locations (`/mnt/c/...`) are deliberately
16
+ * absent: the interop launch cannot work (see .probe), and reporting a found
17
+ * Windows binary as healthy would be a false negative for the known
18
+ * executable-missing error. Unknown platforms probe nothing.
19
+ */
20
+ export declare const DEFAULT_CHROME_PATHS: {
21
+ linux: string[];
22
+ darwin: string[];
23
+ win32: string[];
24
+ };
25
+ /** The default discovery candidate list for one platform; [] probes nothing. */
26
+ export declare function defaultChromePaths(platform?: NodeJS.Platform): string[];
27
+ /**
28
+ * Every path one executable run probes: the row-config candidate list (default
29
+ * the platform list), then the ids the saved rows carry, then the current
30
+ * selection — deduplicated, in this order, so the list reads "what the profile
31
+ * configures, then what the card saved, then what runs".
32
+ * @param entry - validated row config (`chromePaths` is the candidate list).
33
+ * @param savedIds - the saved rows' ids, in row order (see ./catalog.ts).
34
+ * @param effectivePath - the currently selected path, always kept in the list.
35
+ */
36
+ export declare function chromeExecutableCandidates(entry: Pick<ChromeMcpConfig, "chromePaths">, savedIds?: readonly string[], effectivePath?: string): string[];
37
+ //# 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;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB;;;;CAahC,CAAC;AAEF,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,MAAM,EAAE,CAGzF;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACtC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,EAC3C,QAAQ,GAAE,SAAS,MAAM,EAAO,EAChC,aAAa,SAAK,GACnB,MAAM,EAAE,CAeV"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Google Chrome stable-channel locations probed by discovery when
3
+ * `chromePath` is empty — mirrors the upstream (puppeteer) system-channel
4
+ * resolution. WSL Windows-side locations (`/mnt/c/...`) are deliberately
5
+ * absent: the interop launch cannot work (see .probe), and reporting a found
6
+ * Windows binary as healthy would be a false negative for the known
7
+ * executable-missing error. Unknown platforms probe nothing.
8
+ */
9
+ export const DEFAULT_CHROME_PATHS = {
10
+ linux: [
11
+ "/opt/google/chrome/chrome",
12
+ "/usr/bin/google-chrome",
13
+ "/usr/bin/google-chrome-stable",
14
+ "/usr/local/bin/google-chrome",
15
+ "google-chrome"
16
+ ],
17
+ darwin: ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"],
18
+ win32: [
19
+ "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
20
+ "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"
21
+ ]
22
+ };
23
+ /** The default discovery candidate list for one platform; [] probes nothing. */
24
+ export function defaultChromePaths(platform = process.platform) {
25
+ const candidates = DEFAULT_CHROME_PATHS[platform];
26
+ return Array.isArray(candidates) ? [...candidates] : [];
27
+ }
28
+ /**
29
+ * Every path one executable run probes: the row-config candidate list (default
30
+ * the platform list), then the ids the saved rows carry, then the current
31
+ * selection — deduplicated, in this order, so the list reads "what the profile
32
+ * configures, then what the card saved, then what runs".
33
+ * @param entry - validated row config (`chromePaths` is the candidate list).
34
+ * @param savedIds - the saved rows' ids, in row order (see ./catalog.ts).
35
+ * @param effectivePath - the currently selected path, always kept in the list.
36
+ */
37
+ export function chromeExecutableCandidates(entry, savedIds = [], effectivePath = "") {
38
+ const rowPaths = Array.isArray(entry?.chromePaths) ? entry.chromePaths : [];
39
+ const saved = Array.isArray(savedIds) ? savedIds : [];
40
+ const seen = new Set();
41
+ const candidates = [];
42
+ const push = (value) => {
43
+ const path = String(value ?? "").trim();
44
+ if (path === "" || seen.has(path))
45
+ return;
46
+ seen.add(path);
47
+ candidates.push(path);
48
+ };
49
+ for (const path of rowPaths)
50
+ push(path);
51
+ for (const path of saved)
52
+ push(path);
53
+ push(effectivePath);
54
+ return candidates;
55
+ }
56
+ //# sourceMappingURL=candidates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"candidates.js","sourceRoot":"","sources":["../../../src/host/discovery/candidates.ts"],"names":[],"mappings":"AAaA;;;;;;;GAOG;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;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CACtC,KAA2C,EAC3C,WAA8B,EAAE,EAChC,aAAa,GAAG,EAAE;IAElB,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,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,IAAI,CAAC,aAAa,CAAC,CAAC;IACpB,OAAO,UAAU,CAAC;AACtB,CAAC"}
@@ -0,0 +1,18 @@
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 { checkChrome, discoverChrome, scanChromeExecutables } from "./scan.js";
18
+ //# 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,WAAW,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,18 @@
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 { checkChrome, discoverChrome, scanChromeExecutables } from "./scan.js";
18
+ //# 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,WAAW,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Spawn one `chromePath --version` probe (scrubbed parent env, bounded
3
+ * timeout). Resolves the first stdout line (the version); ENOENT rejects with
4
+ * "Chrome executable not found: <path>" carrying code "ENOENT"; a non-zero
5
+ * exit rejects with the first non-empty stderr/stdout line.
6
+ */
7
+ export declare function probeExecutable(target: string): Promise<string>;
8
+ /** True when a candidate path can be handed to the OS for a `--version` probe.
9
+ * A path that is absent (or not executable) never reaches the spawn: a
10
+ * Chrome-less host runs one scan without launching anything. Paths with no
11
+ * directory separator go straight to the spawn so the OS resolves them
12
+ * through `PATH`. */
13
+ export declare function presentOnDisk(candidate: string): boolean;
14
+ /** Identity key used to fold two spellings of the same binary (`google-chrome`
15
+ * resolving onto `/usr/bin/google-chrome`) into one option. Falls back to the
16
+ * path itself when `realpath` cannot resolve it. */
17
+ export declare function identity(candidate: string): string;
18
+ //# sourceMappingURL=probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../../src/host/discovery/probe.ts"],"names":[],"mappings":"AAkBA;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA0C/D;AAED;;;;qBAIqB;AACrB,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAWxD;AAED;;oDAEoD;AACpD,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMlD"}