-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathstart-dev.sh
More file actions
executable file
·150 lines (130 loc) · 4.82 KB
/
Copy pathstart-dev.sh
File metadata and controls
executable file
·150 lines (130 loc) · 4.82 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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/bin/bash
# Start (or attach to) a slot-based Claude Code devcontainer from the Mac terminal.
# Usage: ./start-dev.sh <slot> [--rebuild]
# slot Name for this dev slot (e.g. inky, pinky, blinky).
# Every slot gets its own independent container. /app is baked
# into the image, and poststart.sh force-resets it to origin/main
# when the container is created.
# --rebuild Remove the image and rebuild from scratch.
set -euo pipefail
SLOT=""
REBUILD=false
for arg in "$@"; do
case "$arg" in
--rebuild) REBUILD=true ;;
--*) echo "Unknown option: $arg"; exit 1 ;;
*)
if [ -n "$SLOT" ]; then
echo "Unexpected argument: $arg"; exit 1
fi
SLOT="$arg"
;;
esac
done
if [ -z "$SLOT" ]; then
echo "Usage: ./start-dev.sh <slot> [--rebuild]"
echo ""
echo " slot Name for this dev slot (e.g. inky, pinky, blinky)."
echo " --rebuild Remove and rebuild the Docker image from scratch."
exit 1
fi
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
MAIN_DIR="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel)"
MAIN_NAME="$(basename "$MAIN_DIR")"
IMAGE_NAME="${MAIN_NAME}-image"
ENV_FILE="$SCRIPT_DIR/.devcontainer/devcontainer.env"
CONTAINER_NAME="${MAIN_NAME}_${SLOT}"
WORKSPACE="/app"
# First-run: collect credentials
if [ ! -f "$ENV_FILE" ]; then
bash "$SCRIPT_DIR/.devcontainer/setup.sh"
fi
# Ensure wip_notes/ and wip_outputs/ exist on the host (both gitignored)
if [ ! -d "$MAIN_DIR/wip_notes" ]; then
mkdir -p "$MAIN_DIR/wip_notes"
echo "Created wip_notes/ (read-only agent input). Gitignored."
fi
if [ ! -d "$MAIN_DIR/wip_outputs" ]; then
mkdir -p "$MAIN_DIR/wip_outputs"
echo "Created wip_outputs/ (agent output files). Gitignored."
fi
mkdir -p "$MAIN_DIR/wip_outputs/$SLOT"
WIP_OUTPUTS_SLOT="$MAIN_DIR/wip_outputs/$SLOT"
# Ensure per-slot graphify-out dir exists on the host
GRAPHIFY_HOST="$HOME/dev/graphify-out/$SLOT"
mkdir -p "$GRAPHIFY_HOST"
# --rebuild: remove container and image
if [ "$REBUILD" = true ]; then
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
echo "Removing container '$CONTAINER_NAME'..."
docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true
fi
echo "Removing image '$IMAGE_NAME'..."
docker rmi -f "$IMAGE_NAME" >/dev/null 2>&1 || true
fi
_exec_shell() {
docker exec -it -u vscode -w "$WORKSPACE" \
-e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 -e TERM=xterm-256color \
"$CONTAINER_NAME" zsh -l
}
_cleanup() {
docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true
}
# Container already running — just attach
if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
echo "Attaching to running container '$CONTAINER_NAME'..."
_exec_shell
exit 0
fi
# Build image (cached layers reused if unchanged)
echo "Building image '$IMAGE_NAME'..."
docker build -t "$IMAGE_NAME" -f "$SCRIPT_DIR/docker/Dockerfile" --target dev "$SCRIPT_DIR"
echo ""
echo "Creating container '$CONTAINER_NAME'..."
DOCKER_ARGS=(
--name "$CONTAINER_NAME"
--hostname "$CONTAINER_NAME"
--env-file "$ENV_FILE"
--cpus "${SLOT_CPUS:-3}"
-e LANG=C.UTF-8
-e LC_ALL=C.UTF-8
-e TERM=xterm-256color
-e VULTRON_MAIN_NAME="$MAIN_NAME"
-e WIP_NOTES=/app/wip_notes
-e WIP_OUTPUTS=/app/wip_outputs
-e GRAPHIFY_MAX_WORKERS=4
-v "${MAIN_NAME}-data:/home/vscode/.data"
# NOTE: .devcontainer is NOT mounted. It is baked into the image and belongs
# to the container's own working tree. Mounting the host copy over it made
# one host directory the working tree for every slot plus the host repo, so
# any git operation in one slot dirtied all the others.
-v "$MAIN_DIR/wip_notes:/app/wip_notes:ro"
-v "$WIP_OUTPUTS_SLOT:/app/wip_outputs"
-v "$GRAPHIFY_HOST:/app/graphify-out"
-w "$WORKSPACE"
)
# Mount user-level skills read-only if present on the host
if [ -d "$HOME/.agents/skills" ]; then
DOCKER_ARGS+=(-v "$HOME/.agents/skills:/home/vscode/.agents/skills:ro")
fi
# Mount host .gitconfig so commits use the user's real identity
if [ -f "$HOME/.gitconfig" ]; then
DOCKER_ARGS+=(-v "$HOME/.gitconfig:/home/vscode/.gitconfig:ro")
fi
# Forward SSH agent if available (Docker Desktop on Mac)
if [ -S "/run/host-services/ssh-auth.sock" ]; then
DOCKER_ARGS+=(
-e SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock
-v /run/host-services/ssh-auth.sock:/run/host-services/ssh-auth.sock
)
fi
docker run -d "${DOCKER_ARGS[@]}" "$IMAGE_NAME" sleep infinity
trap _cleanup EXIT
echo ""
echo "Running post-create setup (first time only)..."
docker exec -u vscode -w "$WORKSPACE" "$CONTAINER_NAME" \
bash -l /app/.devcontainer/postcreate.sh
echo ""
docker exec -u vscode -w "$WORKSPACE" "$CONTAINER_NAME" \
bash -l /app/.devcontainer/poststart.sh
_exec_shell