Files
cowork-local/.vibeflow-preview/entrypoint.sh
T
1419587401
CI / test (push) Canceled after 0s
Feature/fsg gamma team ui fix (#3)
## Summary

What changed and why?

## Change Type

- [ ] Cowork feature
- [ ] Bug fix
- [x] Core AI contribution
- [ ] Test / hardening
- [ ] Performance
- [ ] Documentation

## Related Work

Cowork Task:

Core Repo: http://34.143.229.138/gitea-admin/fsg-ai-core-assets

Core AI Issue:

Core Task:

Related PR:

## Scope

What is intentionally included?

What is intentionally NOT included?

## Validation

- [ ] Unit tests
- [ ] Integration tests
- [ ] Manual verification
- [ ] Regression check

Commands / evidence:

## Security Impact

Permission / credential / network / customer data impact:

## Compatibility

- [ ] No breaking change
- [ ] Breaking change documented

## Reviewer Notes

Anything Cowork reviewers should pay attention to.

---------

Co-authored-by: Hiep Ha Van <hiephv3@fpt.com>
Co-authored-by: Nam Pham Dinh Thanh <nampdt@fpt.com>
Co-authored-by: Lam Hoang Van <lamhv7@fpt.com>
Co-authored-by: NamPDT <minhanhpkpro@gmail.com>
Reviewed-on: #3
2026-08-20 12:12:56 +00:00

100 lines
4.4 KiB
Bash

#!/bin/sh
# Boot the Cowork-Local PySide6 desktop app on Qt's built-in VNC server, then
# expose the live GUI to the browser through noVNC + websockify on :6080.
#
# This entrypoint is intended to be run from a `python:3.11-slim-bookworm`
# container via podman-compose. All setup (Qt runtime libs, noVNC, PySide6
# wheels) happens here so we don't need a custom image / Dockerfile.
# Idempotent: reruns are fast (apt reuses debs, pip uses the named cache vol).
set -e
log() { printf '[entrypoint] %s\n' "$*"; }
# ---------------------------------------------------------------------------
# 1. System runtime libraries: Qt6 needs EGL/GL/XCB; noVNC needs websockify.
# ---------------------------------------------------------------------------
if [ ! -f /var/cache/cowork_setup.stamp ]; then
log "installing apt packages (first run only)…"
apt-get update -qq
apt-get install -y --no-install-recommends \
libegl1 libgl1 libglib2.0-0 libdbus-1-3 libfontconfig1 \
libxkbcommon0 libxkbcommon-x11-0 libxcb-cursor0 \
libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 \
libxcb-render-util0 libxcb-shape0 libxcb-sync1 \
libxcb-xfixes0 libxcb-xinerama0 libxcb-xkb1 libxcb-util1 \
libxcomposite1 libxdamage1 libxrandr2 libxss1 libxtst6 \
libxi6 libxrender1 libfreetype6 \
fonts-dejavu fonts-noto-cjk \
netcat-openbsd ca-certificates >/dev/null
rm -rf /var/lib/apt/lists/*
touch /var/cache/cowork_setup.stamp
log "apt setup done."
else
log "apt setup already done (skipping)."
fi
# ---------------------------------------------------------------------------
# 2. Python dependencies (cached in the named `pip-cache` volume).
# `websockify` is shipped as a pip wheel and bundles the noVNC web
# assets under its package `web/` directory, so we don't need the
# (unavailable on slim-bookworm) apt `novnc` / `websockify` packages.
# ---------------------------------------------------------------------------
log "ensuring python deps…"
pip install --no-cache-dir --quiet \
"PySide6>=6.6" "pydantic>=2" requests psutil websockify numpy
log "python deps OK."
# ---------------------------------------------------------------------------
# 3. Make the workspace importable as `cowork_local` (the package name that
# `python -m cowork_local` and the test suite expect). Compose mounts the
# live repo at /workspace; we add a thin symlink at /opt/cowork_local.
# ---------------------------------------------------------------------------
ln -sfn /workspace /opt/cowork_local
export PYTHONPATH=/opt
# ---------------------------------------------------------------------------
# 4. Launch the app on Qt's built-in VNC platform (no Xvfb needed).
# Qt VNC listens on QT_QPA_VNC_HOST:QT_QPA_VNC_PORT (127.0.0.1:5900).
# ---------------------------------------------------------------------------
: > /var/log/app.log
log "launching app on Qt VNC platform…"
python -m cowork_local >/var/log/app.log 2>&1 &
APP_PID=$!
# Wait until the VNC socket accepts a connection (or give up after 60s).
for i in $(seq 1 120); do
if nc -z 127.0.0.1 "${QT_QPA_VNC_PORT:-5900}" 2>/dev/null; then
log "VNC server up on 127.0.0.1:${QT_QPA_VNC_PORT:-5900} (pid ${APP_PID})."
break
fi
if ! kill -0 "${APP_PID}" 2>/dev/null; then
log "app process died before VNC was up; log tail:"
tail -n 60 /var/log/app.log >&2 || true
exit 1
fi
sleep 0.5
done
if ! nc -z 127.0.0.1 "${QT_QPA_VNC_PORT:-5900}" 2>/dev/null; then
log "VNC never came up; log tail:"
tail -n 60 /var/log/app.log >&2 || true
exit 1
fi
# ---------------------------------------------------------------------------
# 5. Bridge browser -> VNC. websockify serves the noVNC web client on :6080
# and proxies WebSocket connections to the raw VNC server. The noVNC web
# assets are bundled inside the websockify pip wheel.
# ---------------------------------------------------------------------------
NOVNC_WEB="$(python - <<'PY'
import os, websockify
print(os.path.join(os.path.dirname(websockify.__file__), "web"))
PY
)"
[ -f "${NOVNC_WEB}/vnc.html" ] || { log "noVNC web assets not found at ${NOVNC_WEB}, aborting."; exit 1; }
log "noVNC web assets: ${NOVNC_WEB}"
log "starting noVNC bridge on 0.0.0.0:6080 -> 127.0.0.1:${QT_QPA_VNC_PORT:-5900}"
exec websockify --web="${NOVNC_WEB}" 0.0.0.0:6080 "127.0.0.1:${QT_QPA_VNC_PORT:-5900}"