Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-gridland-react-singleton.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@prover-coder-ai/docker-git": patch
---

Pin React and React DOM to the Gridland renderer-compatible 19.2.4 release so the CLI menu keeps a single valid React hook dispatcher.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
RUN curl -fsSL https://deb.nodesource.com/setup_24.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& curl -fsSL https://bun.sh/install | bash \
&& npm i -g node-gyp @openai/codex
&& npm i -g node-gyp@12.4.0 @openai/codex

# Create non-root user for SSH
RUN useradd -m -s /bin/bash dev
Expand Down
19 changes: 10 additions & 9 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@
"unrs-resolver"
],
"overrides": {
"react": "19.2.7"
"react": "19.2.4",
"react-dom": "19.2.4"
},
"repository": {
"type": "git",
Expand Down
31 changes: 26 additions & 5 deletions packages/api/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,32 @@ RUN set -eu; \
&& nvidia-ctk runtime configure --runtime=docker \
&& rm -rf /var/lib/apt/lists/*

RUN curl -fsSL https://deb.nodesource.com/setup_24.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& curl -fsSL https://bun.sh/install | bash \
&& npm i -g node-gyp \
&& rm -rf /var/lib/apt/lists/*
RUN set -eu; \
installed=0; \
for attempt in 1 2 3 4 5; do \
rm -rf /var/lib/apt/lists/* /opt/bun; \
if curl -fsSL --retry 5 --retry-all-errors --retry-delay 2 https://deb.nodesource.com/setup_24.x -o /tmp/nodesource-setup.sh \
&& bash /tmp/nodesource-setup.sh \
&& apt-get -o Acquire::Retries=3 install -y --no-install-recommends nodejs \
&& npm install -g --prefix /opt/bun --no-audit --no-fund bun@1.3.11 node-gyp@12.4.0 \
&& node -v \
&& npm -v \
&& bun --version \
&& test "$(bun --version)" = "1.3.11" \
&& node-gyp --version; then \
installed=1; \
break; \
fi; \
echo "controller tooling install attempt ${attempt} failed; retrying..." >&2; \
rm -f /tmp/nodesource-setup.sh; \
sleep $((attempt * 2)); \
done; \
if [ "$installed" != "1" ]; then \
echo "controller tooling install failed after retries" >&2; \
exit 1; \
fi; \
rm -f /tmp/nodesource-setup.sh; \
rm -rf /var/lib/apt/lists/*

FROM controller-base AS workspace-deps

Expand Down
4 changes: 2 additions & 2 deletions packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@
"@gridland/bun": "0.4.3",
"@gridland/web": "0.4.3",
"effect": "^3.21.2",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"react": "19.2.4",
"react-dom": "19.2.4",
"react-reconciler": "^0.33.0",
"ts-morph": "^28.0.0"
},
Expand Down
29 changes: 29 additions & 0 deletions packages/app/tests/docker-git/controller-resource-limits.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,35 @@ describe("API Dockerfile Electron materialization", () => {
}))
})

describe("API Dockerfile controller tooling install", () => {
it.effect("retries network-bound controller tooling downloads", () =>
Effect.gen(function*(_) {
const contents = yield* _(readComposeFile("packages/api/Dockerfile"))
expect(contents).toContain("https://deb.nodesource.com/setup_24.x -o /tmp/nodesource-setup.sh")
expect(contents).toContain("npm install -g --prefix /opt/bun --no-audit --no-fund bun@1.3.11 node-gyp@12.4.0")
expect(contents).toContain("curl -fsSL --retry 5 --retry-all-errors --retry-delay 2")
expect(contents).toContain("for attempt in 1 2 3 4 5; do")
expect(contents).toContain("controller tooling install failed after retries")
expect(contents).toContain("test \"$(bun --version)\" = \"1.3.11\"")
expect(contents).toContain("node-gyp --version")
}))
Comment thread
coderabbitai[bot] marked this conversation as resolved.
})

describe("OpenCode E2E auth bootstrap", () => {
it.effect("retries controller auth commands before the clone scenario", () =>
Effect.gen(function*(_) {
const contents = yield* _(readComposeFile("scripts/e2e/opencode-autoconnect.sh"))
expect(contents).toContain("auth_attempts=3")
expect(contents).toContain(": > \"$AUTH_LOG\"")
expect(contents).toContain("if (")
expect(contents).toContain("dg_run_docker_git \"$REPO_ROOT\" auth codex import")
expect(contents).toContain("dg_run_docker_git \"$REPO_ROOT\" auth codex status")
expect(contents).toContain(") >>\"$AUTH_LOG\" 2>&1")
expect(contents).toContain("auth bootstrap attempt $auth_attempt/$auth_attempts failed")
expect(contents).toContain("docker-git auth bootstrap failed after $auth_attempts attempts")
}))
})

describe("controller resource limit resolution", () => {
it.effect("resolves CPU and RAM defaults to 90% of host resources", () =>
Effect.sync(() => {
Expand Down
37 changes: 36 additions & 1 deletion packages/app/tests/docker-git/gridland-react-singleton.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,46 @@ import { describe, expect, it } from "@effect/vitest"
import { Effect } from "effect"

import rootPackage from "../../../../package.json" with { type: "json" }
import terminalPackage from "../../../terminal/package.json" with { type: "json" }
import appPackage from "../../package.json" with { type: "json" }

// CHANGE: encode the React version resolved for the Gridland Bun renderer.
// WHY: @gridland/bun embeds react-reconciler@0.33.0; Bun resolves that renderer contract to React 19.2.4.
// QUOTE(ISSUE): "TypeError: null is not an object (evaluating 'resolveDispatcher().useCallback')"
// REF: issue-385
// SOURCE: n/a
// FORMAT THEOREM: workspaceReactVersion = rendererReactVersion -> dispatcher(hookCall) != null
// PURITY: CORE
// EFFECT: n/a
// INVARIANT: every workspace React entry resolves to the renderer-compatible singleton version.
// COMPLEXITY: O(1)
const gridlandRendererReactVersion = "19.2.4"

const stripCaret = (value: string): string => value.replace(/^\^/u, "")

// CHANGE: resolve a dependency version from either dependencies or devDependencies.
// WHY: the terminal package exports React components but never renders to the DOM itself,
// so `react-dom` is a devDependency there; the singleton pin must still be enforced
// wherever the dependency is declared. REF: PR-386 CodeRabbit review.
const resolveDepVersion = (
pkg: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> },
name: string
): string => {
const version = pkg.dependencies?.[name] ?? pkg.devDependencies?.[name]
if (version === undefined) {
throw new Error(`Expected ${name} to be declared in dependencies or devDependencies`)
}
return stripCaret(version)
}

describe("Gridland React singleton contract", () => {
it.effect("pins React across workspace dependencies for the Gridland renderer", () =>
Effect.sync(() => {
expect(rootPackage.overrides.react).toBe(appPackage.dependencies.react.replace(/^\^/u, ""))
expect(rootPackage.overrides.react).toBe(gridlandRendererReactVersion)
expect(rootPackage.overrides["react-dom"]).toBe(gridlandRendererReactVersion)
expect(stripCaret(appPackage.dependencies.react)).toBe(gridlandRendererReactVersion)
expect(stripCaret(appPackage.dependencies["react-dom"])).toBe(gridlandRendererReactVersion)
expect(resolveDepVersion(terminalPackage, "react")).toBe(gridlandRendererReactVersion)
expect(resolveDepVersion(terminalPackage, "react-dom")).toBe(gridlandRendererReactVersion)
}))
})
4 changes: 2 additions & 2 deletions packages/terminal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"@effect/platform-node": "^0.107.0",
"@effect/schema": "^0.75.5",
"effect": "^3.21.2",
"react": "^19.2.7",
"react": "19.2.4",
"xterm": "^5.3.0",
"xterm-addon-fit": "^0.8.0"
},
Expand Down Expand Up @@ -55,7 +55,7 @@
"fast-check": "^4.8.0",
"globals": "^17.6.0",
"jscpd": "^4.2.4",
"react-dom": "^19.2.7",
"react-dom": "19.2.4",
"typescript": "^6.0.3",
"typescript-eslint": "^8.60.1",
"vite": "^8.0.16",
Expand Down
25 changes: 20 additions & 5 deletions scripts/e2e/opencode-autoconnect.sh
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,26 @@ OPENCODE_AUTO_CONNECT=1
EOF_ENV

AUTH_LOG="$ROOT/codex-auth.log"
(
cd "$REPO_ROOT"
dg_run_docker_git "$REPO_ROOT" auth codex import --codex-auth "$ROOT/.orch/auth/codex"
dg_run_docker_git "$REPO_ROOT" auth codex status --codex-auth "$ROOT/.orch/auth/codex"
) >"$AUTH_LOG" 2>&1
auth_attempts=3
auth_attempt=1
auth_exit=0
: > "$AUTH_LOG"
while [[ "$auth_attempt" -le "$auth_attempts" ]]; do
if (
cd "$REPO_ROOT"
dg_run_docker_git "$REPO_ROOT" auth codex import --codex-auth "$ROOT/.orch/auth/codex"
dg_run_docker_git "$REPO_ROOT" auth codex status --codex-auth "$ROOT/.orch/auth/codex"
) >>"$AUTH_LOG" 2>&1; then
auth_exit=0
break
else
auth_exit=$?
fi
echo "e2e/opencode-autoconnect: auth bootstrap attempt $auth_attempt/$auth_attempts failed (exit: $auth_exit); retrying..." >&2
auth_attempt="$((auth_attempt + 1))"
sleep 2
done
[[ "$auth_exit" -eq 0 ]] || fail "docker-git auth bootstrap failed after $auth_attempts attempts (last exit: $auth_exit)"

auth_confirmation_count="$(grep -Fc -- "Codex auth imported into controller state (account: ci@example.com)." "$AUTH_LOG" || true)"
[[ "$auth_confirmation_count" -ge 2 ]] \
Expand Down
Loading