Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
95cb1de
feat(pixi): add root pixi.toml for RoboStack Jazzy workspace
charlesmadjeri Aug 29, 2026
e6afe5b
evol(config): add micro_ros_agent and audio_common clone entries
charlesmadjeri Aug 29, 2026
502086f
feat(pixi): add pixi.lock after dependency audit
charlesmadjeri Aug 29, 2026
0263608
evol(launcher): use native workspace paths and drop VNC tools
charlesmadjeri Aug 29, 2026
e412d57
evol(install): run install and launch through Pixi with tmux launcher
charlesmadjeri Aug 29, 2026
cfd8032
evol(docker): remove Docker image and container launch path
charlesmadjeri Aug 29, 2026
dc043c1
feat(tui): drive Lucy install and rebuild via Pixi
charlesmadjeri Aug 29, 2026
79870d0
evol(docs): document Pixi setup, native GUI, and CLI equivalents
charlesmadjeri Aug 29, 2026
9502f26
evol(ci): replace Docker install smoke tests with Pixi
charlesmadjeri Aug 29, 2026
54cb9be
fix(pixi): add binutils and Ninja for colcon gtest builds
charlesmadjeri Aug 29, 2026
8c69f97
fix(launcher): run tmux panes through pixi and forward GUI env
charlesmadjeri Aug 29, 2026
a30b15c
fix(launcher): preserve checkbox state on apply
charlesmadjeri Aug 29, 2026
2aded9e
fix(pixi): use host tmux and simplify colcon build task
charlesmadjeri Aug 29, 2026
116738c
evol(docs): document native Pixi launch
charlesmadjeri Aug 29, 2026
c846f32
chore(nix): remove flake.nix dev shell
charlesmadjeri Aug 29, 2026
bb34c70
feat(scripts): add local RealSense build helper and release doc stub
charlesmadjeri Aug 29, 2026
911265a
evol(install): repair wipes colcon dirs and clarify DEV mode
charlesmadjeri Aug 29, 2026
84cf5f4
fix(launch): exit when tmux is required but missing
charlesmadjeri Aug 29, 2026
772b9d5
evol(ci): panel-install step and tmux launcher smoke on Linux
charlesmadjeri Aug 29, 2026
6d1a573
evol(docs): mark micro_ros_agent and audio_common as optional
charlesmadjeri Aug 29, 2026
83785af
fix(launcher): scope modifier state to the workspace
charlesmadjeri Aug 29, 2026
781cc52
evol(config): add native Pixi launcher local config example
charlesmadjeri Aug 29, 2026
4b7cb74
evol(docs): clarify RealSense local build order and platforms
charlesmadjeri Aug 29, 2026
45c8275
feat(tests): add launcher and repos.json unit tests
charlesmadjeri Aug 29, 2026
7471581
fix(pixi): set GZ_SIM_SYSTEM_PLUGIN_PATH on Windows
charlesmadjeri Aug 29, 2026
8d3fb84
fix(launcher): apply NixOS host GL inside pixi for ros2 launch panes
charlesmadjeri Aug 30, 2026
e02638f
feat(pixi): replace launch-sim with component tasks and dev shell
charlesmadjeri Aug 30, 2026
280687e
evol(docs): refactor README and developer guide for launch workflows
charlesmadjeri Aug 30, 2026
072ad6c
fix(ci): green multi-platform install, build, and workspace tests
charlesmadjeri Aug 30, 2026
b6cd871
fix(ci): run colcon tests without redundant rebuild
charlesmadjeri Aug 30, 2026
388c327
fix(install): prefer ~/.pixi/bin and skip optional repos by default
charlesmadjeri Aug 30, 2026
b6d889d
fix(install): re-solve pixi.lock during --repair
charlesmadjeri Aug 30, 2026
f93d9ae
fix(scripts): use portable CPU count for RealSense build
charlesmadjeri Aug 30, 2026
6739327
feat(test): cover optional repo COLCON_IGNORE behavior
charlesmadjeri Aug 30, 2026
7800a75
evol(launcher): centralize tmux session name
charlesmadjeri Aug 30, 2026
2ebad04
evol(docs): document Pixi auto-upgrade behavior
charlesmadjeri Aug 30, 2026
4613562
fix(pixi): pin cmake to >=3.22,<4
charlesmadjeri Aug 30, 2026
e92825d
fix(install): prompt before Pixi auto-upgrade
charlesmadjeri Aug 30, 2026
7c85ad3
fix(Lucy): restore MIN_TERM_HEIGHT and MIN_TERM_WIDTH
charlesmadjeri Aug 30, 2026
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
14 changes: 14 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,16 @@
PORT_ROSBRIDGE=9090
PORT_CONTROL_PANEL=5000

# Optional GUI workarounds (launcher forwards these into tmux panes):
# LIBGL_ALWAYS_SOFTWARE=1
# QT_QPA_PLATFORM=xcb
# QT_XCB_GL_INTEGRATION=xcb_egl

# NixOS + Pixi/RoboStack Gazebo (scripts/nix_gl_env.sh — required for sim on NixOS):
# Install nixGLIntel on PATH, or use /run/opengl-driver fallback.
# Do not set LUCY_NIX_GL=0 — host GL prepend + EGL are both required.
# __EGL_VENDOR_LIBRARY_FILENAMES=/run/opengl-driver/share/glvnd/egl_vendor.d/50_mesa.json
# GZ_IP=127.0.0.1
# LUCY_NIX_GL_WRAPPER=nixGLIntel
# Robot package for pixi run (default inmoov_urdf):
# LUCY_ROBOT_PACKAGE=thais_urdf
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.sh text eol=lf
*.bash text eol=lf
158 changes: 80 additions & 78 deletions .github/workflows/install-and-launch.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
# Full workspace install (clone + Docker image + rosdep + colcon + yarn) plus a
# non-interactive launch smoke test, on both x86_64 and ARM64 GitHub-hosted runners.
# Pixi + RoboStack workspace install (clone + colcon + yarn) and a headless launch
Comment thread
charlesmadjeri marked this conversation as resolved.
# smoke test on Linux, macOS, and Windows GitHub-hosted runners.
#
# - DEV=false -> install.sh uses `url_https` from config/repos.json (sub-repos are public).
# - CI=true -> install.sh skips the host `xhost` check (no GUI on runners).
# - variant=arm runs on `ubuntu-24.04-arm` with `./install.sh --arm`; the built image
# is then verified to be linux/arm64 (linux/amd64 for the default variant).
# - Runner OS (22.04 or 24.04) is only the CI host. ROS 2 Jazzy always runs inside
# Noble-based images (`ubuntu:24.04` + `ros-jazzy-*` packages; tagged `lucy_ros2:jazzy`).
# - `ubuntu-24.04-arm` is GitHub's hosted ARM64 runner label; there is no 22.04-arm
# standard runner. The container OS stays Noble (24.04) regardless.
# - The launch smoke test uses `./launch_lucy.sh --headless <command>`, which runs a
# single command inside the container (no control panel, no auto Gazebo/RViz).
# - DEV=false -> install.sh uses url_https from config/repos.json.
# - ./install.sh --skip-build clones sub-repos; colcon build runs via pixi run build.

name: Install, Launch & Release

Expand All @@ -19,89 +11,96 @@ on:
push:
branches: [master, dev]
tags:
- 'v*' # Run on version tags like v1.0, v2.3.4
- 'v*'
pull_request:
branches: [master, dev]

permissions:
contents: read

jobs:
install-and-launch:
pixi-install-build-test:
name: Pixi install & build (${{ matrix.runner }})
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.variant }}
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.runner }}
cancel-in-progress: true
runs-on: ${{ matrix.runner }}
timeout-minutes: 120
strategy:
fail-fast: false
matrix:
include:
- variant: default
runner: ubuntu-latest
use_arm_install: false
expected_arch: linux/amd64
- variant: arm
runner: ubuntu-24.04-arm
use_arm_install: true
expected_arch: linux/arm64
- runner: ubuntu-latest
pixi_platform: linux-64
- runner: ubuntu-24.04-arm
pixi_platform: linux-aarch64
- runner: macos-latest
pixi_platform: osx-arm64
- runner: windows-latest
pixi_platform: win-64
env:
DEV: "false"
CI: "true"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- uses: prefix-dev/setup-pixi@v0.10.0
with:
pixi-version: latest
cache: ${{ matrix.pixi_platform != 'win-64' }}
post-cleanup: false

- name: Workspace unit tests
shell: bash
run: pixi run workspace-test

# Make sure no committed/local .env can flip DEV back to true at install time.
- name: Drop workspace .env if present
shell: bash
run: rm -f .env .env.local || true

# Docker Hub metadata/pull flakes (i/o timeout) fail `docker build` before
# any Dockerfile layer runs. Pre-pull with retries so the build reuses cache.
- name: Pre-pull base images (retry on Hub flakes)
- name: Clone sub-repositories (skip colcon)
shell: bash
run: |
pull_with_retry() {
image="$1"
for attempt in 1 2 3 4 5; do
if docker pull "$image"; then
return 0
fi
echo "docker pull ${image} failed (attempt ${attempt}/5), retrying..."
sleep $((attempt * 15))
done
return 1
}
pull_with_retry ubuntu:24.04
chmod +x install.sh launch_lucy.sh
./install.sh --skip-build

- name: Build workspace (colcon)
shell: bash
run: pixi run build

- name: Install control panel (yarn)
shell: bash
run: pixi run panel-install

- name: Run colcon tests
shell: bash
run: pixi run test-only

- name: ROS doctor
shell: bash
run: pixi run doctor

- name: Install (clone + Docker image + rosdep + colcon + yarn)
- name: Launch smoke test (headless)
shell: bash
run: ./launch_lucy.sh --headless ros2 doctor --report

- name: Launcher tmux smoke (Linux)
if: matrix.pixi_platform == 'linux-64'
shell: bash
run: |
chmod +x install.sh launch_lucy.sh
if [ "${{ matrix.use_arm_install }}" = true ]; then
./install.sh --arm
else
./install.sh
fi
chmod +x scripts/ci_tmux_launcher_smoke.sh
LUCY_WS_ROOT="$PWD" ./scripts/ci_tmux_launcher_smoke.sh

- name: Verify Lucy image architecture
- name: Verify Pixi platform
shell: bash
run: |
osarch=$(docker image inspect lucy_ros2:jazzy --format '{{.Os}}/{{.Architecture}}')
echo "lucy_ros2:jazzy -> ${osarch}"
if [ "${osarch}" != "${{ matrix.expected_arch }}" ]; then
echo "::error::Expected ${{ matrix.expected_arch }} after ./install.sh on ${{ matrix.runner }}, got ${osarch}"
got=$(pixi info --json | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('platform', ''))")
echo "pixi platform -> ${got} (expected ${{ matrix.pixi_platform }})"
if [ "${got}" != "${{ matrix.pixi_platform }}" ]; then
echo "::error::Pixi platform mismatch on ${{ matrix.runner }}"
exit 1
fi

# Single command in the container -> bypasses the control-panel / Gazebo / RViz auto-launch.
- name: Launch smoke test (headless, no TTY)
run: ./launch_lucy.sh --headless ros2 doctor --report

# Windows-specific CI. NOTE: GitHub-hosted Windows runners cannot run Linux
# containers (no Hyper-V/nested virtualization, no WSL2), so the heavy install
# step (docker build of the ROS image + colcon) CANNOT run here — that is
# covered for both amd64/arm64 by the Linux `install-and-launch` job above.
# This job verifies the Windows-only pieces on real x64 AND arm64 hardware:
# - host CPU -> Docker platform detection (install_ops.host_container_platform)
# - Lucy.exe builds (PyInstaller) and its bundled --cli imports work
# - the NSIS installer compiles
windows-build-test:
name: Windows build & installer test (${{ matrix.arch }})
strategy:
Expand All @@ -110,15 +109,21 @@ jobs:
include:
- arch: x64
runner: windows-latest
expected_platform: linux/amd64
expected_platform: win-64
- arch: arm64
runner: windows-11-arm
expected_platform: linux/arm64
expected_platform: win-64
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
steps:
- name: Check out repository
uses: actions/checkout@v4
uses: actions/checkout@v5

- uses: prefix-dev/setup-pixi@v0.10.0
with:
pixi-version: latest
cache: false
post-cleanup: false

- name: Set up Python
uses: actions/setup-python@v5
Expand All @@ -128,14 +133,14 @@ jobs:
- name: Generate releases manifest
run: python windows/generate_releases.py

- name: Verify host architecture detection
- name: Verify host Pixi platform detection
shell: pwsh
run: |
$expected = "${{ matrix.expected_platform }}"
$got = (python -c "import sys; sys.path.insert(0,'windows'); import install_ops; print(install_ops.host_container_platform())").Trim()
Write-Host "host_container_platform() -> $got (expected $expected)"
$got = (python -c "import sys; sys.path.insert(0,'windows'); import install_ops; print(install_ops.host_pixi_platform())").Trim()
Write-Host "host_pixi_platform() -> $got (expected $expected)"
if ($got -ne $expected) {
Write-Error "Arch detection mismatch: got '$got', expected '$expected'"
Write-Error "Platform detection mismatch: got '$got', expected '$expected'"
exit 1
}

Expand All @@ -159,8 +164,6 @@ jobs:
dist\Lucy.exe --cli check-prereqs
$code = $LASTEXITCODE
Write-Host "check-prereqs exit code: $code"
# 0 (all present) or 1 (a prereq missing, e.g. no Docker on CI) both mean
# the exe ran fine; >1 = crash. Reset the propagated exit code explicitly.
if ($code -gt 1) { Write-Error "Lucy.exe --cli check-prereqs crashed (exit $code)"; exit 1 }
exit 0

Expand All @@ -175,7 +178,7 @@ jobs:
if (-not (Test-Path "dist/Lucy-Setup-0.0.0-ci.exe")) { Write-Error "Installer not produced"; exit 1 }

- name: Upload Windows artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: lucy-windows-${{ matrix.arch }}
path: |
Expand All @@ -185,15 +188,14 @@ jobs:

build-and-release-windows-exe:
name: Build and Release Windows Executable
# Only run this job when a new tag is pushed
if: startsWith(github.ref, 'refs/tags/')
runs-on: windows-latest
needs: install-and-launch
needs: pixi-install-build-test
permissions:
contents: write # Required to create a release and upload assets
contents: write
steps:
- name: Check out repository
uses: actions/checkout@v4
uses: actions/checkout@v5

- name: Set up Python
uses: actions/setup-python@v5
Expand Down
14 changes: 9 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Pixi
.pixi/

# Workspace (filled by install.sh)
src/

Expand All @@ -24,12 +27,12 @@ __pycache__/
.env
.env.local

# Docker platform choice (./install.sh --arm)
.lucy-docker-platform

# Launcher remembered tick selection (persisted across container restarts)
# Launcher remembered tick selection (persisted across restarts)
.lucy_launcher_state.json

# Launcher runtime modifier state (which core modifiers were applied)
.lucy_launcher_modifiers.json

# Local repo override (forks/branches; takes precedence over config/repos.json)
config/repos.json.local

Expand All @@ -43,4 +46,5 @@ config/install.profile.json
dist/
*.spec

*.local
*.local
.local/
Loading
Loading