@axiomatic-labs/claudeflow 2.13.73 → 2.13.75

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/doctor.js CHANGED
@@ -42,7 +42,9 @@ function readPlaywrightCdpEndpoint(mcpPath) {
42
42
  const flagIdx = entry.args.indexOf('--cdp-endpoint');
43
43
  if (flagIdx === -1) return { state: 'no-flag', parsed };
44
44
  const value = entry.args[flagIdx + 1];
45
- const match = /localhost:(\d+)/.exec(value || '');
45
+ // Accept localhost OR 127.0.0.1 (v2.13.72+ writes the latter explicitly to
46
+ // dodge the IPv4/IPv6 dual-daemon trap — see observer-loopback lint test).
47
+ const match = /(?:localhost|127\.0\.0\.1):(\d+)/.exec(value || '');
46
48
  if (!match) return { state: 'unparseable', value, parsed };
47
49
  return { state: 'ok', port: Number(match[1]), flagIdx, parsed };
48
50
  }
@@ -78,7 +80,7 @@ function checkCdpPortMismatch(cwd) {
78
80
 
79
81
  function applyCdpPortFix(check) {
80
82
  const { mcpPath, expected, parsed, flagIdx } = check.fix;
81
- parsed.mcpServers.playwright.args[flagIdx + 1] = `http://localhost:${expected}`;
83
+ parsed.mcpServers.playwright.args[flagIdx + 1] = `http://127.0.0.1:${expected}`;
82
84
  fs.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + '\n');
83
85
  }
84
86
 
package/lib/install.js CHANGED
@@ -313,6 +313,47 @@ function killStaleObserverDaemon(cwd) {
313
313
  // Swallow — non-fatal. The user can restart manually if needed.
314
314
  }
315
315
  try { fs.unlinkSync(pidPath); } catch {}
316
+
317
+ killStaleBrowserBridge(cwd);
318
+ }
319
+
320
+ // Clean stale Chrome launch lockfiles after an update. The bridge process
321
+ // itself is ephemeral (inject-and-exit), but `.browser-cdp-<port>.pid` is a
322
+ // "have we already launched Chrome this session" lock used by
323
+ // UserPromptSubmit. If Chrome died but the lockfile survived (crash, kill,
324
+ // stale session), the next UserPromptSubmit sees the lock, decides Chrome
325
+ // is already running, skips the launch — and the bridge never runs again,
326
+ // so injected scripts in any surviving tabs keep posting to the old daemon
327
+ // (which we just killed) until manual recovery.
328
+ function killStaleBrowserBridge(cwd) {
329
+ const tmpDir = path.join(cwd, '.claudeflow', 'tmp');
330
+ let entries;
331
+ try {
332
+ entries = fs.readdirSync(tmpDir);
333
+ } catch {
334
+ return;
335
+ }
336
+ const cleaned = [];
337
+ for (const name of entries) {
338
+ if (!/^\.browser-cdp-\d+\.pid$/.test(name)) continue;
339
+ const full = path.join(tmpDir, name);
340
+ let pid;
341
+ try {
342
+ pid = Number(fs.readFileSync(full, 'utf8').trim());
343
+ } catch {
344
+ continue;
345
+ }
346
+ let alive = false;
347
+ if (Number.isFinite(pid) && pid > 1) {
348
+ try { process.kill(pid, 0); alive = true; } catch {}
349
+ }
350
+ if (!alive) {
351
+ try { fs.unlinkSync(full); cleaned.push(name); } catch {}
352
+ }
353
+ }
354
+ if (cleaned.length > 0) {
355
+ ui.success(`Removed ${cleaned.length} stale Chrome lockfile(s) — next prompt will relaunch the bridge cleanly`);
356
+ }
316
357
  }
317
358
 
318
359
  function ensureGlobalCli(version) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiomatic-labs/claudeflow",
3
- "version": "2.13.73",
3
+ "version": "2.13.75",
4
4
  "description": "Claudeflow — AI-powered development toolkit for Claude Code. Skills, agents, hooks, and quality gates that ship production apps.",
5
5
  "bin": {
6
6
  "claudeflow": "./bin/cli.js"