Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .devcontainer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

### Added

#### Startup
- **Container runtime pre-flight check** — validates Docker or Podman is installed and running before attempting to build the devcontainer; aborts with OS-specific remediation guidance (Windows/WSL, macOS, Linux) instead of a cryptic Docker client error

#### README
- **"Why CodeForge?" section** — motivation and value proposition explaining the project's origins as a power user's personal setup
- **Architecture overview** — three-layer diagram (DevContainer → CodeForge Layer → Claude Code) with brief descriptions and link to full architecture docs
Expand Down
2 changes: 2 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"workspaceFolder": "/workspaces",
"workspaceMount": "source=${localWorkspaceFolder},target=/workspaces,type=bind",

"initializeCommand": "bash .devcontainer/scripts/preflight.sh",

Comment on lines +8 to +9
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify CHANGELOG.md entry for preflight check
echo "=== Checking CHANGELOG.md for preflight entry ==="
cat -n .devcontainer/CHANGELOG.md | head -50

echo ""
echo "=== Searching for preflight-related entries ==="
rg -i "preflight|pre-flight|runtime|initialize.*command" .devcontainer/CHANGELOG.md -A 2 -B 2 || echo "No preflight entry found"

Repository: AnExiledDev/CodeForge

Length of output: 6737


🏁 Script executed:

#!/bin/bash
# Check if devcontainer.json changes align with CHANGELOG
echo "=== Current initializeCommand in devcontainer.json ==="
rg -A 1 "initializeCommand" .devcontainer/devcontainer.json || echo "Not found in devcontainer.json"

echo ""
echo "=== Check CLAUDE.md for config system documentation ==="
rg -i "initialize|preflight|runtime" .devcontainer/CLAUDE.md || echo "No references to preflight in CLAUDE.md"

Repository: AnExiledDev/CodeForge

Length of output: 282


CHANGELOG.md entry confirmed; add initializeCommand documentation to CLAUDE.md.

The CHANGELOG.md entry for the container runtime pre-flight check exists and is well-formatted under "### Added → #### Startup" (lines 17–18). However, per project learnings, config system changes must be reflected in .devcontainer/CLAUDE.md. The initializeCommand configuration change is not currently documented there.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.devcontainer/devcontainer.json around lines 8 - 9, Add documentation for
the new initializeCommand option to .devcontainer/CLAUDE.md: describe that
"initializeCommand" is now used to run the preflight script (bash
.devcontainer/scripts/preflight.sh) before the container starts, show the exact
JSON property name initializeCommand and an example snippet, and note its
purpose (container runtime pre-flight checks) and any effects on startup order;
update the CLAUDE.md "Startup" or configuration section accordingly so the
change referenced in CHANGELOG.md is documented.

"mounts": [
{
"source": "codeforge-claude-config-${devcontainerId}",
Expand Down
113 changes: 113 additions & 0 deletions .devcontainer/scripts/preflight.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-3.0-only
# Copyright (c) 2026 Marcus Krueger
# Pre-flight check: validates a container runtime is available on the host.
# Runs via initializeCommand BEFORE any container build/pull/start.
Comment on lines +1 to +5
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if CLAUDE.md exists and whether preflight.sh is already documented
if [ -f ".devcontainer/CLAUDE.md" ]; then
  echo "=== Checking if preflight.sh is mentioned in CLAUDE.md ==="
  rg -n "preflight" .devcontainer/CLAUDE.md || echo "preflight.sh not mentioned in CLAUDE.md"
  
  echo ""
  echo "=== Looking for setup scripts section in CLAUDE.md ==="
  rg -n -B2 -A5 "setup.*\.sh|scripts/" .devcontainer/CLAUDE.md | head -40
else
  echo "CLAUDE.md not found"
fi

Repository: AnExiledDev/CodeForge

Length of output: 1309


🏁 Script executed:

#!/bin/bash
# List all scripts in the devcontainer scripts directory
echo "=== Scripts in .devcontainer/scripts/ ==="
ls -la .devcontainer/scripts/ 2>/dev/null || echo "scripts directory not found"

echo ""
echo "=== Check git status for preflight.sh ==="
git status .devcontainer/scripts/preflight.sh 2>/dev/null || echo "preflight.sh not in git"

echo ""
echo "=== Check devcontainer.json for initializeCommand ==="
rg -A2 "initializeCommand" .devcontainer/devcontainer.json

Repository: AnExiledDev/CodeForge

Length of output: 1184


🏁 Script executed:

#!/bin/bash
# Get CLAUDE.md to understand what's documented about initialization and scripts
wc -l .devcontainer/CLAUDE.md
echo ""
echo "=== Full CLAUDE.md content ==="
cat -n .devcontainer/CLAUDE.md

Repository: AnExiledDev/CodeForge

Length of output: 11604


Update CLAUDE.md to document the initialization flow, including preflight.sh.

The scripts/ directory comment (line 23) states "Setup scripts (run via postStartCommand)" but this is incomplete—preflight.sh runs via initializeCommand (before container build), while other scripts run via postStartCommand (after container starts). Per the learnings, config system changes must be documented in .devcontainer/CLAUDE.md. Either:

  1. Clarify line 23 to note both initializeCommand and postStartCommand hooks, or
  2. Add a section documenting the container initialization sequence with preflight.sh's purpose (validating container runtime availability).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.devcontainer/scripts/preflight.sh around lines 1 - 5, Update
.devcontainer/CLAUDE.md to document the initialization flow: describe that
scripts/preflight.sh is executed via initializeCommand before any container
build/pull/start to validate container runtime availability, and that other
scripts in scripts/ are run via postStartCommand after the container starts;
also edit the scripts/ directory comment (the line referencing "Setup scripts
(run via postStartCommand)") to either mention both initializeCommand and
postStartCommand or add a new section in CLAUDE.md explaining the two hooks,
their order, and the purpose of preflight.sh so readers can understand when and
why it runs.


set -euo pipefail

# --- OS detection ---

detect_os() {
if [[ -f /proc/version ]] && grep -qi 'microsoft\|wsl' /proc/version 2>/dev/null; then
echo "wsl"
elif [[ "$(uname -s)" == "Darwin" ]]; then
echo "macos"
else
echo "linux"
fi
}

# --- Timeout wrapper (macOS lacks coreutils timeout) ---

run_with_timeout() {
local seconds="$1"
shift
if command -v timeout &>/dev/null; then
timeout "$seconds" "$@" &>/dev/null 2>&1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Redundant redirection.

&>/dev/null already redirects both stdout and stderr, making 2>&1 unnecessary.

🧹 Proposed fix
-        timeout "$seconds" "$@" &>/dev/null 2>&1
+        timeout "$seconds" "$@" &>/dev/null
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
timeout "$seconds" "$@" &>/dev/null 2>&1
timeout "$seconds" "$@" &>/dev/null
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.devcontainer/scripts/preflight.sh at line 27, The timeout invocation uses
redundant redirection: change the invocation of timeout (the line with timeout
"$seconds" "$@" &>/dev/null 2>&1) to remove the duplicate redirection so only a
single combined redirect is used (e.g., keep &>/dev/null) ensuring stdout and
stderr are silenced without the extra 2>&1 token.

else
# Fallback for macOS: background + kill
"$@" &>/dev/null 2>&1 &
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Same redundant redirection issue.

🧹 Proposed fix
-        "$@" &>/dev/null 2>&1 &
+        "$@" &>/dev/null &
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"$@" &>/dev/null 2>&1 &
"$@" &>/dev/null &
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.devcontainer/scripts/preflight.sh at line 30, The command invocation
currently uses redundant redirection '"$@" &>/dev/null 2>&1 &' which duplicates
stderr redirection; update the backgrounded command to use a single, correct
redirection form (either '"$@" &>/dev/null &' or the more portable '"$@"
>/dev/null 2>&1 &') so stdout and stderr are suppressed without duplication;
change the line containing the '"$@"' invocation accordingly.

local pid=$!
(sleep "$seconds" && kill "$pid" 2>/dev/null) &
local watchdog=$!
if wait "$pid" 2>/dev/null; then
kill "$watchdog" 2>/dev/null
wait "$watchdog" 2>/dev/null
return 0
else
kill "$watchdog" 2>/dev/null
wait "$watchdog" 2>/dev/null
return 1
fi
fi
}

# --- Runtime detection ---

check_runtime() {
local runtime="$1"
if ! command -v "$runtime" &>/dev/null; then
return 1
fi
if run_with_timeout 5 "$runtime" info; then
return 0
fi
return 1
}

# --- Main ---

for runtime in docker podman; do
if check_runtime "$runtime"; then
exit 0
fi
done

# No working runtime found — determine why and advise

found_binary=""
for runtime in docker podman; do
if command -v "$runtime" &>/dev/null; then
found_binary="$runtime"
break
fi
done

HOST_OS="$(detect_os)"

echo ""
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ CodeForge: Container runtime not available ║"
echo "╚══════════════════════════════════════════════════════════════╝"
echo ""

if [[ -n "$found_binary" ]]; then
echo " Found '$found_binary' but the daemon is not responding."
echo ""
case "$HOST_OS" in
wsl)
echo " Fix: Start Docker Desktop and enable WSL 2 integration:"
echo " Settings → Resources → WSL Integration"
;;
macos)
echo " Fix: Start Docker Desktop:"
echo " open -a Docker"
;;
linux)
echo " Fix: Start the Docker daemon:"
echo " sudo systemctl start docker"
;;
esac
else
echo " No container runtime (docker or podman) found in PATH."
echo ""
echo " Install Docker Desktop:"
echo " https://www.docker.com/products/docker-desktop/"
echo ""
echo " Or install Podman:"
echo " https://podman.io/getting-started/installation"
fi

echo ""
exit 1
Loading