feat: migrate browser automation from Playwright MCP to CLI, fix headless setting

Major changes across 21 files (755 additions, 196 deletions):

Browser Automation Migration:
- Add versioned project migration system (prompts.py) with content-based
  detection and section-level regex replacement for coding/testing prompts
- Migrate STEP 5 (browser verification) and BROWSER AUTOMATION sections
  in coding prompt template to use playwright-cli commands
- Migrate STEP 2 and AVAILABLE TOOLS sections in testing prompt template
- Migration auto-runs at agent startup (autonomous_agent_demo.py), copies
  playwright-cli skill, scaffolds .playwright/cli.config.json, updates
  .gitignore, and stamps .migration_version file
- Add playwright-cli command validation to security allowlist (security.py)
  with tests for allowed subcommands and blocked eval/run-code

Headless Browser Setting Fix:
- Add _apply_playwright_headless() to process_manager.py that reads/updates
  .playwright/cli.config.json before agent subprocess launch
- Remove dead PLAYWRIGHT_HEADLESS env var that was never consumed
- Settings UI toggle now correctly controls visible browser window

Playwright CLI Auto-Install:
- Add ensurePlaywrightCli() to lib/cli.js for npm global entry point
- Add playwright-cli detection + npm install to start.bat, start.sh,
  start_ui.bat, start_ui.sh for all startup paths

Other Improvements:
- Add project folder path tooltip to ProjectSelector.tsx dropdown items
- Remove legacy Playwright MCP server configuration from client.py
- Update CLAUDE.md with playwright-cli skill documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Auto
2026-02-11 13:37:03 +02:00
parent f285db1ad3
commit e9873a2642
21 changed files with 754 additions and 195 deletions

View File

@@ -125,14 +125,18 @@ def cleanup_stale_temp(max_age_seconds: int = MAX_AGE_SECONDS) -> dict:
def cleanup_project_screenshots(project_dir: Path, max_age_seconds: int = 300) -> dict:
"""
Clean up stale screenshot files from the project root.
Clean up stale Playwright CLI artifacts from the project.
Playwright browser verification can leave .png files in the project
directory. This removes them after they've aged out (default 5 minutes).
The Playwright CLI daemon saves screenshots, snapshots, and other artifacts
to `{project_dir}/.playwright-cli/`. This removes them after they've aged
out (default 5 minutes).
Also cleans up legacy screenshot patterns from the project root (from the
old Playwright MCP server approach).
Args:
project_dir: Path to the project directory.
max_age_seconds: Maximum age in seconds before a screenshot is deleted.
max_age_seconds: Maximum age in seconds before an artifact is deleted.
Defaults to 5 minutes (300 seconds).
Returns:
@@ -141,13 +145,33 @@ def cleanup_project_screenshots(project_dir: Path, max_age_seconds: int = 300) -
cutoff_time = time.time() - max_age_seconds
stats: dict = {"files_deleted": 0, "bytes_freed": 0, "errors": []}
screenshot_patterns = [
# Clean up .playwright-cli/ directory (new CLI approach)
playwright_cli_dir = project_dir / ".playwright-cli"
if playwright_cli_dir.exists():
for item in playwright_cli_dir.iterdir():
if not item.is_file():
continue
try:
mtime = item.stat().st_mtime
if mtime < cutoff_time:
size = item.stat().st_size
item.unlink(missing_ok=True)
if not item.exists():
stats["files_deleted"] += 1
stats["bytes_freed"] += size
logger.debug(f"Deleted playwright-cli artifact: {item}")
except Exception as e:
stats["errors"].append(f"Failed to delete {item}: {e}")
logger.debug(f"Failed to delete artifact {item}: {e}")
# Legacy cleanup: root-level screenshot patterns (from old MCP server approach)
legacy_patterns = [
"feature*-*.png",
"screenshot-*.png",
"step-*.png",
]
for pattern in screenshot_patterns:
for pattern in legacy_patterns:
for item in project_dir.glob(pattern):
if not item.is_file():
continue
@@ -159,14 +183,14 @@ def cleanup_project_screenshots(project_dir: Path, max_age_seconds: int = 300) -
if not item.exists():
stats["files_deleted"] += 1
stats["bytes_freed"] += size
logger.debug(f"Deleted project screenshot: {item}")
logger.debug(f"Deleted legacy screenshot: {item}")
except Exception as e:
stats["errors"].append(f"Failed to delete {item}: {e}")
logger.debug(f"Failed to delete screenshot {item}: {e}")
if stats["files_deleted"] > 0:
mb_freed = stats["bytes_freed"] / (1024 * 1024)
logger.info(f"Screenshot cleanup: {stats['files_deleted']} files, {mb_freed:.1f} MB freed")
logger.info(f"Artifact cleanup: {stats['files_deleted']} files, {mb_freed:.1f} MB freed")
return stats