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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ recreates it directly with the Wave Docker Compose override. This avoids a known
Dev Containers CLI hang where the container starts but the CLI never returns, so
Wave never reaches the final interactive shell.

For a running container, the launcher displays startup status immediately and
skips profile-launcher copies when the previously installed content hash still
matches.

The fallback override mounts shell and agent configuration from the WSL home
directory so the container shell keeps the same `zsh`, Oh My Zsh, Powerlevel10k,
Git, GitHub CLI, SSH, and agent settings.
Expand Down
70 changes: 51 additions & 19 deletions bin/wave-container-shell.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ workdir="/workspace"
shell_path="zsh"
block_title="pyBench"
check_only=false
profile_launcher_marker="/usr/local/share/workbenches/profile-launchers.sha256"
bench_dir="$workbenches_root/devBenches/pyBench"
compose_file="$bench_dir/.devcontainer/docker-compose.yml"

Expand Down Expand Up @@ -91,6 +92,13 @@ if ! command -v docker >/dev/null 2>&1; then
exit 1
fi

if [[ "$check_only" != true ]]; then
if [[ -t 1 ]]; then
printf '\033]0;%s\007' "$block_title"
fi
echo "Opening '$block_title' container shell..."
fi

run_devcontainer_up() {
local remove_flag=()
local devcontainer_timeout="${WAVE_DEVCONTAINER_UP_TIMEOUT:-25s}"
Expand Down Expand Up @@ -304,31 +312,55 @@ install_ai_profile_launchers() {
local pi_launcher="$workbenches_root/base-image/files/pi-profile"
[[ -f "$claude_launcher" ]] || return 0

docker cp "$claude_launcher" "$container:/usr/local/bin/claude-profile"
docker exec --user root "$container" sh -c \
'chmod 0755 /usr/local/bin/claude-profile && ln -sfn claude-profile /usr/local/bin/pclaude'
if [[ -f "$codex_launcher" ]]; then
docker cp "$codex_launcher" "$container:/usr/local/bin/codex-profile"
docker exec --user root "$container" sh -c \
'chmod 0755 /usr/local/bin/codex-profile && ln -sfn codex-profile /usr/local/bin/pcodex'
fi
if [[ -f "$provider_launcher" ]]; then
docker cp "$provider_launcher" "$container:/usr/local/bin/provider-profile"
local launchers=(
"$claude_launcher"
"$codex_launcher"
"$provider_launcher"
"$pi_launcher"
)
local bundle_hash
bundle_hash="$(
for launcher in "${launchers[@]}"; do
if [[ -f "$launcher" ]]; then
sha256sum "$launcher" | awk '{print $1}'
else
printf '%s\n' missing
fi
done | sha256sum | awk '{print $1}'
)"

local installed_hash
installed_hash="$(docker exec --user root "$container" sh -c "cat '$profile_launcher_marker' 2>/dev/null" || true)"
if [[ "$installed_hash" != "$bundle_hash" ]]; then
docker cp "$claude_launcher" "$container:/usr/local/bin/claude-profile"
docker exec --user root "$container" sh -c \
'chmod 0755 /usr/local/bin/provider-profile
for name in gemini-profile pgemini grok-profile pgrok glm-profile zai-profile pglm pzai; do
ln -sfn provider-profile "/usr/local/bin/$name"
done'
fi
if [[ -f "$pi_launcher" ]]; then
docker cp "$pi_launcher" "$container:/usr/local/bin/pi-profile"
'chmod 0755 /usr/local/bin/claude-profile && ln -sfn claude-profile /usr/local/bin/pclaude'
if [[ -f "$codex_launcher" ]]; then
docker cp "$codex_launcher" "$container:/usr/local/bin/codex-profile"
docker exec --user root "$container" sh -c \
'chmod 0755 /usr/local/bin/codex-profile && ln -sfn codex-profile /usr/local/bin/pcodex'
fi
if [[ -f "$provider_launcher" ]]; then
docker cp "$provider_launcher" "$container:/usr/local/bin/provider-profile"
docker exec --user root "$container" sh -c \
'chmod 0755 /usr/local/bin/provider-profile
for name in gemini-profile pgemini grok-profile pgrok glm-profile zai-profile pglm pzai; do
ln -sfn provider-profile "/usr/local/bin/$name"
done'
fi
if [[ -f "$pi_launcher" ]]; then
docker cp "$pi_launcher" "$container:/usr/local/bin/pi-profile"
docker exec --user root "$container" sh -c \
'chmod 0755 /usr/local/bin/pi-profile && ln -sfn pi-profile /usr/local/bin/ppi'
fi
docker exec --user root "$container" sh -c \
'chmod 0755 /usr/local/bin/pi-profile && ln -sfn pi-profile /usr/local/bin/ppi'
"mkdir -p '$(dirname "$profile_launcher_marker")' && printf '%s\n' '$bundle_hash' > '$profile_launcher_marker'"
fi

docker exec --user root "$container" sh -c \
"mkdir -p '/home/${container_user}/.local/bin' && chown '${container_user}:${container_user}' '/home/${container_user}/.local' '/home/${container_user}/.local/bin'"
docker exec --user "$container_user" "$container" sh -c \
'if [ ! -e "$HOME/.local/bin/claude" ]; then ln -s /usr/local/bin/claude "$HOME/.local/bin/claude"; fi'
'ln -sfn /usr/local/bin/claude "$HOME/.local/bin/claude"'
}

ensure_container_history
Expand Down
4 changes: 4 additions & 0 deletions docs/workbenches-widgets.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ shell with `wave-container-shell.sh`. The launcher makes sure the Docker
container exists, starts it if needed, and runs an interactive login `zsh` shell
inside the container.

The launcher prints an `Opening ...` status immediately. Shared AI profile
launchers are synchronized only when their combined content hash changes, so a
healthy running bench is not delayed by repeated `docker cp` operations.

The widget title is set in two ways:

- terminal OSC title escape
Expand Down