Skip to content

Commit a06e2c5

Browse files
committed
Split Playwright browser runtime template
1 parent 09c8174 commit a06e2c5

6 files changed

Lines changed: 107 additions & 111 deletions

File tree

packages/lib/src/core/templates-entrypoint/base.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ EOF
186186
chmod 0644 "$DOCKER_GIT_SSHD_CONF" || true`
187187

188188
export const renderEntrypointSshd = (): string =>
189-
String.raw`# 5) Run sshd in foreground (log to stderr for CI/debuggability) and stop nested browser on container shutdown
189+
String
190+
.raw`# 5) Run sshd in foreground (log to stderr for CI/debuggability) and stop nested browser on container shutdown
190191
docker_git_run_sshd() {
191192
local sshd_pid=""
192193

packages/lib/src/core/templates.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@ import type { ResolvedComposeResourceLimits } from "./resource-limits.js"
33
import { renderEntrypoint } from "./templates-entrypoint.js"
44
import { type ComposeResourceLimits, renderDockerCompose } from "./templates/docker-compose.js"
55
import { renderDockerfile } from "./templates/dockerfile.js"
6-
import {
7-
renderPlaywrightBrowserDockerfile,
8-
renderPlaywrightBrowserRuntime,
9-
renderPlaywrightStartExtra
10-
} from "./templates/playwright.js"
6+
import { renderPlaywrightBrowserRuntime } from "./templates/playwright-browser-runtime.js"
7+
import { renderPlaywrightBrowserDockerfile, renderPlaywrightStartExtra } from "./templates/playwright.js"
118

129
export type FileSpec =
1310
| { readonly _tag: "File"; readonly relativePath: string; readonly contents: string; readonly mode?: number }

packages/lib/src/core/templates/docker-compose.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,7 @@ const buildPlaywrightFragments = (
114114
maybePlaywrightEnv:
115115
` MCP_PLAYWRIGHT_ENABLE: "1"\n MCP_PLAYWRIGHT_CDP_ENDPOINT: "http://127.0.0.1:9223"\n DOCKER_GIT_PROJECT_CONTAINER_NAME: "${config.containerName}"\n DOCKER_GIT_BROWSER_CONTAINER_NAME: "${browserContainerName}"\n DOCKER_GIT_BROWSER_IMAGE_NAME: "${browserImageName}"\n DOCKER_GIT_BROWSER_VOLUME_NAME: "${browserVolumeName}"\n${
116116
renderBrowserLimitEnv("DOCKER_GIT_BROWSER_CPU_LIMIT", resourceLimits?.cpuLimit)
117-
}${
118-
renderBrowserLimitEnv("DOCKER_GIT_BROWSER_RAM_LIMIT", resourceLimits?.ramLimit)
119-
}`,
117+
}${renderBrowserLimitEnv("DOCKER_GIT_BROWSER_RAM_LIMIT", resourceLimits?.ramLimit)}`,
120118
maybeBrowserVolume: ` ${browserVolumeName}:`
121119
}
122120
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
const playwrightBrowserRuntimeScript = String.raw`#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
docker_git_browser_log() {
5+
printf '%s\n' "[docker-git-browser] $*" >&2
6+
}
7+
8+
docker_git_browser_has_docker() {
9+
command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1
10+
}
11+
12+
docker_git_browser_context_dir() {
13+
printf '%s\n' "\${DOCKER_GIT_BROWSER_CONTEXT_DIR:-/opt/docker-git/browser}"
14+
}
15+
16+
docker_git_stop_playwright_browser() {
17+
local container_name="\${DOCKER_GIT_BROWSER_CONTAINER_NAME:-}"
18+
if [[ -z "$container_name" ]]; then
19+
return 0
20+
fi
21+
if ! docker_git_browser_has_docker; then
22+
return 0
23+
fi
24+
docker rm -f "$container_name" >/dev/null 2>&1 || true
25+
}
26+
27+
docker_git_start_playwright_browser() {
28+
if [[ "\${MCP_PLAYWRIGHT_ENABLE:-0}" != "1" ]]; then
29+
docker_git_stop_playwright_browser || true
30+
return 0
31+
fi
32+
33+
local container_name="\${DOCKER_GIT_BROWSER_CONTAINER_NAME:-}"
34+
local image_name="\${DOCKER_GIT_BROWSER_IMAGE_NAME:-}"
35+
local volume_name="\${DOCKER_GIT_BROWSER_VOLUME_NAME:-}"
36+
local main_container="\${DOCKER_GIT_PROJECT_CONTAINER_NAME:-}"
37+
local context_dir
38+
context_dir="$(docker_git_browser_context_dir)"
39+
40+
if [[ -z "$container_name" || -z "$image_name" || -z "$volume_name" || -z "$main_container" ]]; then
41+
docker_git_browser_log "missing browser runtime configuration; skipping nested browser start"
42+
return 0
43+
fi
44+
if ! docker_git_browser_has_docker; then
45+
docker_git_browser_log "Docker API is unavailable; skipping nested browser start"
46+
return 0
47+
fi
48+
if [[ ! -f "$context_dir/Dockerfile.browser" ]]; then
49+
docker_git_browser_log "browser Dockerfile is missing at $context_dir/Dockerfile.browser"
50+
return 0
51+
fi
52+
53+
docker_git_browser_log "building $image_name"
54+
docker build -t "$image_name" -f "$context_dir/Dockerfile.browser" "$context_dir" >/var/log/docker-git-browser-build.log 2>&1 || {
55+
docker_git_browser_log "browser image build failed; see /var/log/docker-git-browser-build.log"
56+
return 0
57+
}
58+
59+
docker_git_stop_playwright_browser || true
60+
docker volume create "$volume_name" >/dev/null
61+
62+
local args=(
63+
run
64+
-d
65+
--name "$container_name"
66+
--label "docker-git.browser=1"
67+
--label "docker-git.project-container=$main_container"
68+
--network "container:$main_container"
69+
--shm-size "2g"
70+
-e "VNC_NOPW=1"
71+
-e "MCP_PLAYWRIGHT_CDP_GUARD=\${MCP_PLAYWRIGHT_CDP_GUARD:-1}"
72+
-e "MCP_PLAYWRIGHT_BLOCK_BROWSER_CLOSE=\${MCP_PLAYWRIGHT_BLOCK_BROWSER_CLOSE:-1}"
73+
-v "$volume_name:/data"
74+
)
75+
76+
if [[ -n "\${DOCKER_GIT_BROWSER_CPU_LIMIT:-}" ]]; then
77+
args+=(--cpus "$DOCKER_GIT_BROWSER_CPU_LIMIT")
78+
fi
79+
if [[ -n "\${DOCKER_GIT_BROWSER_RAM_LIMIT:-}" ]]; then
80+
args+=(--memory "$DOCKER_GIT_BROWSER_RAM_LIMIT" --memory-swap "$DOCKER_GIT_BROWSER_RAM_LIMIT")
81+
fi
82+
83+
docker_git_browser_log "starting $container_name inside $main_container network namespace"
84+
docker "\${args[@]}" "$image_name" >/dev/null || {
85+
docker_git_browser_log "failed to start $container_name"
86+
return 0
87+
}
88+
}
89+
`
90+
91+
// CHANGE: manage the Playwright browser as a nested Docker container owned by the project container.
92+
// WHY: issue #306 follow-up requires browser containers to inherit project lifecycle while keeping separate limits.
93+
// QUOTE(ТЗ): "пусть он поднимается внутри dg-issues1 а не где-то из вне"
94+
// REF: issue-306-browser-nested-runtime
95+
// SOURCE: n/a
96+
// FORMAT THEOREM: start(main) -> running(browser) with network(browser) = container:main OR logged_warning
97+
// PURITY: SHELL
98+
// EFFECT: shell commands executed by generated entrypoint
99+
// INVARIANT: browser data volume is preserved; runtime cleanup removes only the browser container
100+
// COMPLEXITY: O(build + docker-run)/O(1)
101+
export const renderPlaywrightBrowserRuntime = (): string => playwrightBrowserRuntimeScript

packages/lib/src/core/templates/playwright.ts

Lines changed: 0 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -269,104 +269,3 @@ fi
269269
echo "extra services started"
270270
exit 0
271271
`
272-
273-
// CHANGE: manage the Playwright browser as a nested Docker container owned by the project container.
274-
// WHY: issue #306 follow-up requires browser containers to inherit project lifecycle while keeping separate limits.
275-
// QUOTE(ТЗ): "пусть он поднимается внутри dg-issues1 а не где-то из вне"
276-
// REF: issue-306-browser-nested-runtime
277-
// SOURCE: n/a
278-
// FORMAT THEOREM: start(main) -> running(browser) with network(browser) = container:main OR logged_warning
279-
// PURITY: SHELL
280-
// EFFECT: shell commands executed by generated entrypoint
281-
// INVARIANT: browser data volume is preserved; runtime cleanup removes only the browser container
282-
// COMPLEXITY: O(build + docker-run)/O(1)
283-
export const renderPlaywrightBrowserRuntime = (): string =>
284-
String.raw`#!/usr/bin/env bash
285-
set -euo pipefail
286-
287-
docker_git_browser_log() {
288-
printf '%s\n' "[docker-git-browser] $*" >&2
289-
}
290-
291-
docker_git_browser_has_docker() {
292-
command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1
293-
}
294-
295-
docker_git_browser_context_dir() {
296-
printf '%s\n' "\${DOCKER_GIT_BROWSER_CONTEXT_DIR:-/opt/docker-git/browser}"
297-
}
298-
299-
docker_git_stop_playwright_browser() {
300-
local container_name="\${DOCKER_GIT_BROWSER_CONTAINER_NAME:-}"
301-
if [[ -z "$container_name" ]]; then
302-
return 0
303-
fi
304-
if ! docker_git_browser_has_docker; then
305-
return 0
306-
fi
307-
docker rm -f "$container_name" >/dev/null 2>&1 || true
308-
}
309-
310-
docker_git_start_playwright_browser() {
311-
if [[ "\${MCP_PLAYWRIGHT_ENABLE:-0}" != "1" ]]; then
312-
docker_git_stop_playwright_browser || true
313-
return 0
314-
fi
315-
316-
local container_name="\${DOCKER_GIT_BROWSER_CONTAINER_NAME:-}"
317-
local image_name="\${DOCKER_GIT_BROWSER_IMAGE_NAME:-}"
318-
local volume_name="\${DOCKER_GIT_BROWSER_VOLUME_NAME:-}"
319-
local main_container="\${DOCKER_GIT_PROJECT_CONTAINER_NAME:-}"
320-
local context_dir
321-
context_dir="$(docker_git_browser_context_dir)"
322-
323-
if [[ -z "$container_name" || -z "$image_name" || -z "$volume_name" || -z "$main_container" ]]; then
324-
docker_git_browser_log "missing browser runtime configuration; skipping nested browser start"
325-
return 0
326-
fi
327-
if ! docker_git_browser_has_docker; then
328-
docker_git_browser_log "Docker API is unavailable; skipping nested browser start"
329-
return 0
330-
fi
331-
if [[ ! -f "$context_dir/Dockerfile.browser" ]]; then
332-
docker_git_browser_log "browser Dockerfile is missing at $context_dir/Dockerfile.browser"
333-
return 0
334-
fi
335-
336-
docker_git_browser_log "building $image_name"
337-
docker build -t "$image_name" -f "$context_dir/Dockerfile.browser" "$context_dir" >/var/log/docker-git-browser-build.log 2>&1 || {
338-
docker_git_browser_log "browser image build failed; see /var/log/docker-git-browser-build.log"
339-
return 0
340-
}
341-
342-
docker_git_stop_playwright_browser || true
343-
docker volume create "$volume_name" >/dev/null
344-
345-
local args=(
346-
run
347-
-d
348-
--name "$container_name"
349-
--label "docker-git.browser=1"
350-
--label "docker-git.project-container=$main_container"
351-
--network "container:$main_container"
352-
--shm-size "2g"
353-
-e "VNC_NOPW=1"
354-
-e "MCP_PLAYWRIGHT_CDP_GUARD=\${MCP_PLAYWRIGHT_CDP_GUARD:-1}"
355-
-e "MCP_PLAYWRIGHT_BLOCK_BROWSER_CLOSE=\${MCP_PLAYWRIGHT_BLOCK_BROWSER_CLOSE:-1}"
356-
-v "$volume_name:/data"
357-
)
358-
359-
if [[ -n "\${DOCKER_GIT_BROWSER_CPU_LIMIT:-}" ]]; then
360-
args+=(--cpus "$DOCKER_GIT_BROWSER_CPU_LIMIT")
361-
fi
362-
if [[ -n "\${DOCKER_GIT_BROWSER_RAM_LIMIT:-}" ]]; then
363-
args+=(--memory "$DOCKER_GIT_BROWSER_RAM_LIMIT" --memory-swap "$DOCKER_GIT_BROWSER_RAM_LIMIT")
364-
fi
365-
366-
docker_git_browser_log "starting $container_name inside $main_container network namespace"
367-
docker "\${args[@]}" "$image_name" >/dev/null || {
368-
docker_git_browser_log "failed to start $container_name"
369-
return 0
370-
}
371-
}
372-
`

packages/lib/src/usecases/projects.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ export {
55
type ProjectRuntimeResourceProfile,
66
type ProjectRuntimeStartAction,
77
type ProjectRuntimeState,
8-
type ProjectRuntimeStopReason,
98
projectRuntimeStateRelativePath,
9+
type ProjectRuntimeStopReason,
1010
readProjectRuntimeState,
1111
recordProjectRuntimeActivity,
1212
recordProjectRuntimeResourceProfile,

0 commit comments

Comments
 (0)