podman run -d returns before the container process is running. CS Core's claude-code check immediately calls our wrapper, which found the container not yet running and exited 1 — causing the "claude-code not found" error. Add a poll loop (10 x 0.5s) that waits for State.Running=true before setting PATH and launching CS Core. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
127 lines
5.4 KiB
Bash
127 lines
5.4 KiB
Bash
#!/usr/bin/env bash
|
|
# container.sh — generate Option B container scripts for a project
|
|
|
|
generate_container_scripts() {
|
|
local project_dir="$1"
|
|
local project_name="$2"
|
|
local slug="$3"
|
|
local container_name="cs-${slug}"
|
|
|
|
info "Generating container scripts (Option B)..."
|
|
|
|
mkdir -p "$project_dir/bin"
|
|
|
|
# ── bin/claude — wrapper that runs claude inside the agents container ──
|
|
cat > "$project_dir/bin/claude" <<WRAPPER
|
|
#!/usr/bin/env bash
|
|
# Claude Code wrapper — runs claude inside the agents container.
|
|
# CS Core on the host calls this instead of the real claude binary.
|
|
CONTAINER_NAME="${container_name}"
|
|
RUNTIME="\$(command -v podman || command -v docker || true)"
|
|
|
|
if [[ -z "\$RUNTIME" ]]; then
|
|
echo "[claude-wrapper] Error: podman or docker not found" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! "\$RUNTIME" container inspect "\$CONTAINER_NAME" --format '{{.State.Running}}' 2>/dev/null | grep -q true; then
|
|
echo "[claude-wrapper] Error: container '\$CONTAINER_NAME' is not running." >&2
|
|
echo "[claude-wrapper] Run ./start.sh from your project directory first." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Pass through TTY if available, relay working directory into container
|
|
if [ -t 0 ]; then
|
|
exec "\$RUNTIME" exec -it --workdir "\$PWD" "\$CONTAINER_NAME" claude "\$@"
|
|
else
|
|
exec "\$RUNTIME" exec -i --workdir "\$PWD" "\$CONTAINER_NAME" claude "\$@"
|
|
fi
|
|
WRAPPER
|
|
chmod +x "$project_dir/bin/claude"
|
|
|
|
# ── start.sh — build image, start container, launch CS Core ──────────
|
|
cat > "$project_dir/start.sh" <<START
|
|
#!/usr/bin/env bash
|
|
set -uo pipefail
|
|
SCRIPT_DIR="\$(cd "\$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_DIR="\$SCRIPT_DIR"
|
|
CONTAINER_NAME="${container_name}"
|
|
IMAGE_NAME="${slug}"
|
|
RUNTIME="\$(command -v podman || command -v docker || true)"
|
|
CS_CORE="\${CS_CORE_DIR:-\$HOME/.context-studio/core}"
|
|
|
|
if [[ -z "\$RUNTIME" ]]; then
|
|
echo "Error: podman or docker not found." >&2; exit 1
|
|
fi
|
|
if [[ ! -d "\$CS_CORE" ]]; then
|
|
echo "Error: context-studio-core not found at \$CS_CORE" >&2
|
|
echo "Run the Context Studio Wizard first." >&2; exit 1
|
|
fi
|
|
|
|
# ── Build image if missing ───────────────────────────────────────────────
|
|
if ! "\$RUNTIME" image exists "\$IMAGE_NAME" 2>/dev/null; then
|
|
echo "→ Building container image '\$IMAGE_NAME'..."
|
|
"\$RUNTIME" build -t "\$IMAGE_NAME" "\$PROJECT_DIR/.devcontainer/" \
|
|
|| { echo "Image build failed." >&2; exit 1; }
|
|
fi
|
|
|
|
# ── Stop stale container ─────────────────────────────────────────────────
|
|
"\$RUNTIME" rm -f "\$CONTAINER_NAME" 2>/dev/null || true
|
|
|
|
# ── Start agents container ───────────────────────────────────────────────
|
|
# Mount project at the same absolute path so host and container paths match.
|
|
# CS Core sets agent working dirs to host paths; the wrapper relays PWD.
|
|
echo "→ Starting agents container '\$CONTAINER_NAME'..."
|
|
"\$RUNTIME" run -d \\
|
|
--name "\$CONTAINER_NAME" \\
|
|
-v "\$PROJECT_DIR:\$PROJECT_DIR" \\
|
|
-v "\$HOME/.anthropic:\$HOME/.anthropic:ro" \\
|
|
-e ANTHROPIC_API_KEY="\${ANTHROPIC_API_KEY:-}" \\
|
|
-e CS_WORKFLOW_DIR="\$PROJECT_DIR/workflow" \\
|
|
-e PROJECT_ROOT_DIR="\$PROJECT_DIR" \\
|
|
"\$IMAGE_NAME" \\
|
|
sleep infinity
|
|
|
|
# ── Wait for container to be running ────────────────────────────────────
|
|
echo -n "→ Waiting for container..."
|
|
for _i in 1 2 3 4 5 6 7 8 9 10; do
|
|
if "\$RUNTIME" container inspect "\$CONTAINER_NAME" --format '{{.State.Running}}' 2>/dev/null | grep -q true; then
|
|
echo " ready."
|
|
break
|
|
fi
|
|
echo -n "."
|
|
sleep 0.5
|
|
done
|
|
if ! "\$RUNTIME" container inspect "\$CONTAINER_NAME" --format '{{.State.Running}}' 2>/dev/null | grep -q true; then
|
|
echo ""
|
|
echo "Error: container failed to start." >&2; exit 1
|
|
fi
|
|
|
|
# ── Put claude wrapper first on PATH ────────────────────────────────────
|
|
export PATH="\$PROJECT_DIR/bin:\$PATH"
|
|
|
|
# ── Launch CS Core on the host ───────────────────────────────────────────
|
|
echo "→ Starting Context Studio Core..."
|
|
CS_CORE_DIR="\$CS_CORE" \\
|
|
CS_WORKFLOW_DIR="\$PROJECT_DIR/workflow" \\
|
|
PROJECT_ROOT_DIR="\$PROJECT_DIR" \\
|
|
node "\$CS_CORE/core/start.js"
|
|
|
|
# ── CS Core exited — stop container ─────────────────────────────────────
|
|
echo "→ Stopping agents container..."
|
|
"\$RUNTIME" rm -f "\$CONTAINER_NAME" 2>/dev/null || true
|
|
START
|
|
chmod +x "$project_dir/start.sh"
|
|
|
|
# ── stop.sh — forcefully stop the container ───────────────────────────
|
|
cat > "$project_dir/stop.sh" <<STOP
|
|
#!/usr/bin/env bash
|
|
CONTAINER_NAME="${container_name}"
|
|
RUNTIME="\$(command -v podman || command -v docker || true)"
|
|
echo "→ Stopping \$CONTAINER_NAME..."
|
|
"\$RUNTIME" rm -f "\$CONTAINER_NAME" 2>/dev/null && echo "→ Done." || echo "→ Container was not running."
|
|
STOP
|
|
chmod +x "$project_dir/stop.sh"
|
|
|
|
success "Generated: start.sh stop.sh bin/claude"
|
|
}
|