-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontainer-entrypoint.sh
More file actions
executable file
·135 lines (119 loc) · 4.9 KB
/
container-entrypoint.sh
File metadata and controls
executable file
·135 lines (119 loc) · 4.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env bash
# container-entrypoint.sh — Runs INSIDE the Claude container.
# Writes MCP config, installs CLAUDE.md, launches Claude.
# Repo clone is lazy — Claude calls the clone_repo MCP tool when needed.
#
# Required env: CLAUDEBOX_MCP_URL, SESSION_UUID
# Prompt: /workspace/prompt.txt (mounted by host)
# Optional env: CLAUDEBOX_RESUME_ID
set -euxo pipefail
trap 'echo ""; echo "━━━ Process exited ━━━"' EXIT
# Ensure cargo/rust tools are on PATH
export PATH="$HOME/.cargo/bin:$PATH"
MCP_URL="${CLAUDEBOX_MCP_URL:?required}"
SESSION_UUID="${SESSION_UUID:?required}"
RESUME_ID="${CLAUDEBOX_RESUME_ID:-}"
MODEL="${CLAUDEBOX_MODEL:-}"
PROFILE="${CLAUDEBOX_PROFILE:-default}"
PROMPT_FILE="/workspace/prompt.txt"
PROFILE_DIR="/opt/claudebox-profile"
echo "━━━ Container Bootstrap ━━━"
echo "MCP: $MCP_URL"
echo "Session: $SESSION_UUID"
echo "Profile: $PROFILE"
[ -n "$RESUME_ID" ] && echo "Resume: $RESUME_ID"
[ -n "$MODEL" ] && echo "Model: $MODEL"
# ── Step 1: MCP config ──────────────────────────────────────────
cat > /tmp/mcp.json <<EOF
{
"mcpServers": {
"claudebox": {
"type": "http",
"url": "$MCP_URL"
}
}
}
EOF
# ── Step 2: Write session metadata CLAUDE.md ─────────────────────
# Profile instructions live in $PROFILE_DIR/CLAUDE.md (loaded via --add-dir).
# This file just injects session-specific context into the workspace.
mkdir -p /workspace/.claude
cat > /workspace/.claude/CLAUDE.md <<METAEOF
# Session
- Profile: $PROFILE
- Session: $SESSION_UUID
- MCP: $MCP_URL
$([ -n "$RESUME_ID" ] && echo "- Resuming: $RESUME_ID")
$([ -n "$MODEL" ] && echo "- Model: $MODEL")
METAEOF
# ── Step 3: Read prompt ──────────────────────────────────────────
if [ ! -f "$PROMPT_FILE" ]; then
echo "ERROR: $PROMPT_FILE not found" >&2
exit 1
fi
PROMPT=$(cat "$PROMPT_FILE")
# ── Step 3b: Pre-clone repo from reference if available ──────────
REPO_NAME="${CLAUDEBOX_REPO_NAME:-}"
BASE_BRANCH="${CLAUDEBOX_BASE_BRANCH:-next}"
REPO_DIR="/workspace/${REPO_NAME}"
if [ -n "$REPO_NAME" ] && [ -d "/reference-repo/.git" ] && [ ! -d "${REPO_DIR}/.git" ]; then
echo ""
echo "━━━ Pre-cloning $REPO_NAME (sparse) from reference ━━━"
git config --global --add safe.directory /reference-repo/.git
git config --global --add safe.directory "$REPO_DIR"
# Sparse clone: only checkout .claude/ dirs (skills, settings, CLAUDE.md)
# Claude will populate the full tree via clone_repo when it needs to work
git clone --shared --no-checkout /reference-repo/.git "$REPO_DIR" 2>&1 || true
if [ -d "${REPO_DIR}/.git" ]; then
cd "$REPO_DIR"
# Autodetect .claude-related paths from the reference repo
CLAUDE_PATHS=$(git ls-tree -r -d --name-only HEAD 2>/dev/null | grep -E '(^\.claude$|/\.claude$)' || true)
if [ -n "$CLAUDE_PATHS" ]; then
git sparse-checkout set --cone $CLAUDE_PATHS 2>/dev/null || true
else
git sparse-checkout set --cone .claude 2>/dev/null || true
fi
# Try to checkout the base branch
git checkout --detach "origin/${BASE_BRANCH}" 2>/dev/null \
|| git checkout --detach origin/main 2>/dev/null \
|| git checkout --detach HEAD 2>/dev/null \
|| true
echo "Pre-cloned (sparse) at $(git rev-parse --short HEAD 2>/dev/null || echo '???')"
fi
elif [ -n "$REPO_NAME" ] && [ -d "${REPO_DIR}/.git" ]; then
echo "Repo already exists at $REPO_DIR"
cd "$REPO_DIR"
fi
# Set working directory: prefer repo dir if it exists, else /workspace
WORK_DIR="$REPO_DIR"
[ ! -d "$WORK_DIR" ] && WORK_DIR="/workspace"
echo ""
echo "━━━ Launching Claude ━━━"
echo ""
cd "$WORK_DIR"
# ── Step 4: Run Claude (or CLAUDE_BINARY override) ────────────────
CLAUDE_BIN="${CLAUDE_BINARY:-claude}"
COMMON_ARGS=(--print --dangerously-skip-permissions --mcp-config /tmp/mcp.json -p "$PROMPT")
[ -n "$MODEL" ] && COMMON_ARGS+=(--model "$MODEL")
# Give Claude read/write access to the profile directory (skills, CLAUDE.md, etc.)
[ -d "$PROFILE_DIR" ] && COMMON_ARGS+=(--add-dir "$PROFILE_DIR")
set +e
if [ -n "$RESUME_ID" ]; then
"$CLAUDE_BIN" "${COMMON_ARGS[@]}" --resume "$RESUME_ID" --fork-session
exit_code=$?
# Fall back to fresh session if resume fails (e.g. JSONL from old mount path)
if [ "$exit_code" -ne 0 ]; then
echo ""
echo "━━━ Resume failed (exit $exit_code), starting fresh session ━━━"
echo ""
RESUME_ID=""
fi
fi
if [ -z "$RESUME_ID" ]; then
"$CLAUDE_BIN" "${COMMON_ARGS[@]}" --session-id "$SESSION_UUID"
exit_code=$?
fi
set -e
echo ""
echo "━━━ Exit: $exit_code ━━━"
exit "$exit_code"