run.sh asks which host folder Claude may access, using the desktop's folder picker (zenity, or kdialog on KDE; terminal prompt otherwise), and mounts it read-write at /workspace. It opens at the last folder used, refuses / and $HOME, and can be skipped with --workspace DIR. The image creates /workspace and a ~/workspace symlink to it. Closing Claude Desktop's window only hides the app, which left the container running invisibly. The new entrypoint launch-claude.sh watches the app's X windows and quits it once none is open or minimized, so the container exits with it. run.sh adds --init for signal handling and reaping. Also add .gitignore for workspace/ and .env. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 lines
1.6 KiB
Bash
Executable File
47 lines
1.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Container entrypoint: run Claude Desktop and stop when its window is closed.
|
|
#
|
|
# Closing the window only hides the app (it keeps running for the tray icon,
|
|
# which GNOME doesn't show), so the container would keep running invisibly.
|
|
# This watches the app's X windows and quits the app once none of them is
|
|
# open or minimized. The container then exits with it.
|
|
|
|
set -u
|
|
|
|
claude-desktop "$@" &
|
|
app=$!
|
|
|
|
stop_app() { kill -TERM "$app" 2>/dev/null; wait "$app"; exit $?; }
|
|
trap stop_app TERM INT HUP
|
|
|
|
host="$(hostname)"
|
|
|
|
# True if any of this container's Claude windows is Normal (shown) or Iconic
|
|
# (minimized). A closed window is Withdrawn or loses WM_STATE altogether.
|
|
# WM_CLIENT_MACHINE filters out Claude windows from other containers or apps
|
|
# on the same X server.
|
|
window_open() {
|
|
local w props
|
|
for w in $(xwininfo -root -tree 2>/dev/null \
|
|
| awk '/\("com\.anthropic\.claude" "com\.anthropic\.Claude"\)/ {print $1}'); do
|
|
props="$(xprop -id "$w" WM_CLIENT_MACHINE WM_STATE 2>/dev/null)" || continue
|
|
[[ "$props" == *"WM_CLIENT_MACHINE(STRING) = \"$host\""* ]] || continue
|
|
[[ "$props" =~ "window state: "(Normal|Iconic) ]] && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
seen=0 # only arm the check after the first window has appeared
|
|
misses=0 # require a few consecutive misses to ride out brief remaps
|
|
while kill -0 "$app" 2>/dev/null; do
|
|
sleep 1 & wait $!
|
|
if window_open; then
|
|
seen=1 misses=0
|
|
elif (( seen )) && (( ++misses >= 3 )); then
|
|
echo "launch-claude: window closed, quitting Claude Desktop" >&2
|
|
stop_app
|
|
fi
|
|
done
|
|
|
|
wait "$app"
|