@monoes/monodesign 1.2.24 → 1.2.25

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.
@@ -175,6 +175,31 @@ function createMonobrowsePage(mb, client, sessionId, targetId, port) {
175
175
  };
176
176
  }
177
177
 
178
+ // monobrowse's "the CDP endpoint never opened in time" errors: port 0 waits for
179
+ // DevToolsActivePort, a forced port for the listener itself. Other launch
180
+ // failures (no Chrome, spawn refused, Chrome exited, port squatted) would only
181
+ // fail the same way again.
182
+ const CDP_PORT_TIMEOUT_RE = /did not report a CDP port in .* within \d+ms|failed to start on port \d+ within \d+ms/;
183
+
184
+ // Chrome's first launch on a cold Windows CI runner can take longer than the
185
+ // whole launch timeout to open its CDP port (#583), while every launch after it
186
+ // in the same job is quick. So a timeout gets one more attempt. monobrowse has
187
+ // already killed the timed-out Chrome; its profile dir is dropped and the retry
188
+ // gets a new one, because a leftover Chrome process could still hold the old
189
+ // dir's singleton lock and the retry would hand off to it and exit.
190
+ async function launchWithColdStartRetry(launch, config) {
191
+ for (let attempt = 1; ; attempt++) {
192
+ const userDataDir = mkdtempSync(join(tmpdir(), 'monodesign-cdp-'));
193
+ try {
194
+ const port = await launch({ ...config, userDataDir });
195
+ return { port, userDataDir };
196
+ } catch (error) {
197
+ removeProfileDir(userDataDir);
198
+ if (attempt >= 2 || !CDP_PORT_TIMEOUT_RE.test(error?.message ?? '')) throw error;
199
+ }
200
+ }
201
+ }
202
+
178
203
  async function launchMonobrowseBrowser(options = {}) {
179
204
  const mb = await import('@monoes/monobrowse');
180
205
  const headless = options.headless ?? true;
@@ -210,8 +235,10 @@ async function launchMonobrowseBrowser(options = {}) {
210
235
  // where this bites: its singleton lock survives the previous Chrome being
211
236
  // force-killed, and outlives the port being released. A unique dir removes
212
237
  // the sharing entirely rather than racing the lock's cleanup.
213
- const userDataDir = mkdtempSync(join(tmpdir(), 'monodesign-cdp-'));
214
- const launchedPort = await mb.launchBrowser({ port, headless, args: launchArgs, launchTimeoutMs, userDataDir });
238
+ const { port: launchedPort, userDataDir } = await launchWithColdStartRetry(
239
+ mb.launchBrowser,
240
+ { port, headless, args: launchArgs, launchTimeoutMs },
241
+ );
215
242
  // Control connection (to the initial about:blank tab) — used for lifecycle
216
243
  // commands; detection pages get their own dedicated connections.
217
244
  const control = await mb.connectToTarget(launchedPort);
@@ -334,6 +361,7 @@ export {
334
361
  launchDetectionBrowser,
335
362
  launchMonobrowseBrowser,
336
363
  launchPuppeteerBrowser,
364
+ launchWithColdStartRetry,
337
365
  normalizeBrowserHandle,
338
366
  wrapPuppeteerBrowser,
339
367
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monoes/monodesign",
3
- "version": "1.2.24",
3
+ "version": "1.2.25",
4
4
  "description": "Frontend design intelligence for AI agents — design tokens, antipattern detection, and the monodesign skill",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",