diff --git a/packages/app/src/docker-git/cli/usage.ts b/packages/app/src/docker-git/cli/usage.ts index 5f0bb18a..39e303fa 100644 --- a/packages/app/src/docker-git/cli/usage.ts +++ b/packages/app/src/docker-git/cli/usage.ts @@ -81,6 +81,8 @@ Container runtime env (set via .orch/env/project.env): DOCKER_GIT_ZSH_AUTOSUGGEST_STRATEGY=... Suggestion sources (default: history completion) MCP_PLAYWRIGHT_ISOLATED=1|0 Isolated browser contexts (recommended for many Codex; default: 1) MCP_PLAYWRIGHT_CDP_ENDPOINT=http://... Override CDP endpoint (default: http://dg--browser:9223) + MCP_PLAYWRIGHT_RETRY_ATTEMPTS= Retry attempts for browser sidecar startup wait (default: 10) + MCP_PLAYWRIGHT_RETRY_DELAY= Delay between retry attempts (default: 2) Auth providers: github, gh GitHub CLI auth (tokens saved to env file) diff --git a/packages/lib/src/core/templates/dockerfile.ts b/packages/lib/src/core/templates/dockerfile.ts index 30053b8e..ba7238bf 100644 --- a/packages/lib/src/core/templates/dockerfile.ts +++ b/packages/lib/src/core/templates/dockerfile.ts @@ -105,8 +105,39 @@ if [[ -z "$CDP_ENDPOINT" ]]; then CDP_ENDPOINT="http://__SERVICE_NAME__-browser:9223" fi +# CHANGE: add retry logic for browser sidecar startup wait +# WHY: the browser container may take time to initialize, causing MCP server to fail on first attempt +# QUOTE(issue-123): "Почему MCP сервер лежит с ошибкой?" +# REF: issue-123 +# SOURCE: n/a +# FORMAT THEOREM: forall t in [1..max_attempts]: retry(t) -> eventually(cdp_ready) OR timeout_error +# PURITY: SHELL +# INVARIANT: script exits only after cdp_ready OR all retries exhausted +# COMPLEXITY: O(max_attempts * timeout_per_attempt) +MCP_PLAYWRIGHT_RETRY_ATTEMPTS="\${MCP_PLAYWRIGHT_RETRY_ATTEMPTS:-10}" +MCP_PLAYWRIGHT_RETRY_DELAY="\${MCP_PLAYWRIGHT_RETRY_DELAY:-2}" + +fetch_cdp_version() { + curl -sSf --connect-timeout 3 --max-time 10 -H 'Host: 127.0.0.1:9222' "\${CDP_ENDPOINT%/}/json/version" 2>/dev/null +} + +JSON="" +for attempt in $(seq 1 "$MCP_PLAYWRIGHT_RETRY_ATTEMPTS"); do + if JSON="$(fetch_cdp_version)"; then + break + fi + if [[ "$attempt" -lt "$MCP_PLAYWRIGHT_RETRY_ATTEMPTS" ]]; then + echo "docker-git-playwright-mcp: waiting for browser sidecar (attempt $attempt/$MCP_PLAYWRIGHT_RETRY_ATTEMPTS)..." >&2 + sleep "$MCP_PLAYWRIGHT_RETRY_DELAY" + fi +done + +if [[ -z "$JSON" ]]; then + echo "docker-git-playwright-mcp: failed to connect to CDP endpoint $CDP_ENDPOINT after $MCP_PLAYWRIGHT_RETRY_ATTEMPTS attempts" >&2 + exit 1 +fi + # kechangdev/browser-vnc binds Chromium CDP on 127.0.0.1:9222; it also host-checks HTTP requests. -JSON="$(curl -sSf --connect-timeout 3 --max-time 10 -H 'Host: 127.0.0.1:9222' "\${CDP_ENDPOINT%/}/json/version")" WS_URL="$(printf "%s" "$JSON" | node -e 'const fs=require("fs"); const j=JSON.parse(fs.readFileSync(0,"utf8")); process.stdout.write(j.webSocketDebuggerUrl || "")')" if [[ -z "$WS_URL" ]]; then echo "docker-git-playwright-mcp: webSocketDebuggerUrl missing" >&2 diff --git a/packages/lib/tests/usecases/mcp-playwright.test.ts b/packages/lib/tests/usecases/mcp-playwright.test.ts index dd45763d..f853b4d6 100644 --- a/packages/lib/tests/usecases/mcp-playwright.test.ts +++ b/packages/lib/tests/usecases/mcp-playwright.test.ts @@ -120,6 +120,15 @@ describe("enableMcpPlaywrightProjectFiles", () => { const dockerfileAfter = yield* _(fs.readFileString(path.join(outDir, "Dockerfile"))) expect(dockerfileAfter).toContain("@playwright/mcp") + // CHANGE: verify retry logic is included in docker-git-playwright-mcp wrapper + // WHY: issue-123 requires retry mechanism to handle browser sidecar startup delays + // QUOTE(issue-123): "Почему MCP сервер лежит с ошибкой?" + // REF: issue-123 + expect(dockerfileAfter).toContain("MCP_PLAYWRIGHT_RETRY_ATTEMPTS") + expect(dockerfileAfter).toContain("MCP_PLAYWRIGHT_RETRY_DELAY") + expect(dockerfileAfter).toContain("fetch_cdp_version()") + expect(dockerfileAfter).toContain("waiting for browser sidecar") + const browserDockerfileExists = yield* _(fs.exists(path.join(outDir, "Dockerfile.browser"))) const startExtraExists = yield* _(fs.exists(path.join(outDir, "mcp-playwright-start-extra.sh"))) expect(browserDockerfileExists).toBe(true)