Boot live installer session and narrow install-time contract (Sam & Codex)
This commit is contained in:
parent
d59cc76f30
commit
3a9954f9ec
21 changed files with 359 additions and 175 deletions
|
|
@ -85,7 +85,7 @@ sudo ./build.sh --skip-fetch
|
|||
- Wizard screen 1: Tailscale auth key (pre-filled if baked into build.cfg)
|
||||
- Wizard screen 2: Assistant name + domain
|
||||
- Wizard screen 3: Timezone
|
||||
- Optional: LLM provider, Telegram
|
||||
- Provider keys, Telegram, and browser sign-in are configured after first boot in the controlplane
|
||||
- Setup runs automatically (5–10 min)
|
||||
|
||||
4. **Desktop boots** (if display detected) or headless mode (VPS/cloud)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
FREEBSD_VERSION="15.0-RELEASE"
|
||||
FREEBSD_ARCH="amd64"
|
||||
FREEBSD_MEMSTICK_URL="https://download.freebsd.org/releases/ISO-IMAGES/15.0/FreeBSD-${FREEBSD_VERSION}-${FREEBSD_ARCH}-memstick.img"
|
||||
FREEBSD_MEMSTICK_SHA256_URL="${FREEBSD_MEMSTICK_URL}.SHA256"
|
||||
FREEBSD_RELEASE_SERIES="${FREEBSD_VERSION%-RELEASE}"
|
||||
FREEBSD_ISO_BASE_URL="https://download.freebsd.org/releases/${FREEBSD_ARCH}/${FREEBSD_ARCH}/ISO-IMAGES/${FREEBSD_RELEASE_SERIES}"
|
||||
FREEBSD_MEMSTICK_URL="${FREEBSD_ISO_BASE_URL}/FreeBSD-${FREEBSD_VERSION}-${FREEBSD_ARCH}-memstick.img"
|
||||
FREEBSD_MEMSTICK_SHA256_URL="${FREEBSD_ISO_BASE_URL}/CHECKSUM.SHA256-FreeBSD-${FREEBSD_VERSION}-${FREEBSD_ARCH}"
|
||||
|
||||
# Output image
|
||||
# User-facing date format: DD.mmm.YYYY (per AGENTS.md convention)
|
||||
|
|
|
|||
276
build.sh
276
build.sh
|
|
@ -15,6 +15,7 @@
|
|||
# Requirements (run on FreeBSD host):
|
||||
# pkg install curl # for fetching
|
||||
# pkg install node24 npm-node24 # to bundle clawdie-ai node_modules for offline firstboot
|
||||
# pkg install qt6-base qt6-declarative qt6-buildtools # to build the live QML installer
|
||||
# pkg install (root) # for step 5-6 (mdconfig, mount)
|
||||
#
|
||||
# The tmp/packages/ directory produced here is dual-purpose:
|
||||
|
|
@ -30,6 +31,7 @@ PKG_REPO_DIR="${TMP_DIR}/packages"
|
|||
NPM_GLOBALS_DIR="${TMP_DIR}/npm-globals"
|
||||
CACHE_DIR="${TMP_DIR}/cache"
|
||||
OUTPUT_DIR="${TMP_DIR}/output"
|
||||
LIVE_SESSION_DIR="${SCRIPT_DIR}/live/installer-session"
|
||||
|
||||
. "${SCRIPT_DIR}/build.cfg"
|
||||
|
||||
|
|
@ -96,10 +98,230 @@ pkg_list_all() {
|
|||
"${PKG_LIST_DIR}/pkg-list-jails.txt" \
|
||||
"${PKG_LIST_DIR}/pkg-list-desktop-base.txt" \
|
||||
"${PKG_LIST_DIR}/pkg-list-lumina.txt" \
|
||||
"${PKG_LIST_DIR}/pkg-list-live-installer.txt" \
|
||||
"${PKG_LIST_DIR}/pkg-list-nvidia-all.txt" \
|
||||
| grep -v '^#' | grep -v '^$' | sort -u
|
||||
}
|
||||
|
||||
pkg_list_live_installer() {
|
||||
cat \
|
||||
"${PKG_LIST_DIR}/pkg-list-desktop-base.txt" \
|
||||
"${PKG_LIST_DIR}/pkg-list-lumina.txt" \
|
||||
"${PKG_LIST_DIR}/pkg-list-live-installer.txt" \
|
||||
| grep -v '^#' \
|
||||
| grep -v '^$' \
|
||||
| grep -v -E '^(hal|lumina-filemanager|lumina-open)$' \
|
||||
| sort -u
|
||||
}
|
||||
|
||||
set_config_line() {
|
||||
_file="$1"
|
||||
_assignment="$2"
|
||||
_name=$(echo "$_assignment" | cut -d= -f1)
|
||||
mkdir -p "$(dirname "$_file")"
|
||||
touch "$_file"
|
||||
if grep -q "^${_name}=" "$_file" 2>/dev/null; then
|
||||
sed -i '' "s|^${_name}=.*|${_assignment}|" "$_file"
|
||||
else
|
||||
echo "$_assignment" >> "$_file"
|
||||
fi
|
||||
}
|
||||
|
||||
pkg_archive_for() {
|
||||
_pkg_name="$1"
|
||||
find "${PKG_REPO_DIR}/All" -type f -name "${_pkg_name}-*.pkg" | sort | tail -1
|
||||
}
|
||||
|
||||
mount_memstick_rootfs() {
|
||||
_memstick_mount="$1"
|
||||
_memstick_slice_img="${CACHE_DIR}/memstick-freebsd-slice.img"
|
||||
_memstick_ufs_img="${CACHE_DIR}/memstick-rootfs.img"
|
||||
|
||||
mkdir -p "$_memstick_mount"
|
||||
rm -f "$_memstick_slice_img" "$_memstick_ufs_img"
|
||||
|
||||
MD_SRC=$(mdconfig -a -t vnode -f "$MEMSTICK")
|
||||
|
||||
_slice_meta=$(
|
||||
fdisk "/dev/${MD_SRC}" \
|
||||
| awk '
|
||||
/sysid 165 / { want = 1; next }
|
||||
want && $1 == "start" {
|
||||
gsub(",", "", $2)
|
||||
gsub(",", "", $4)
|
||||
print $2 " " $4
|
||||
exit
|
||||
}
|
||||
'
|
||||
)
|
||||
_slice_start=$(echo "$_slice_meta" | awk '{print $1}')
|
||||
_slice_size=$(echo "$_slice_meta" | awk '{print $2}')
|
||||
if [ -z "${_slice_start:-}" ] || [ -z "${_slice_size:-}" ]; then
|
||||
echo "ERROR: could not determine FreeBSD slice start in ${MEMSTICK}"
|
||||
mdconfig -d -u "${MD_SRC}" 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
truncate -s "$((_slice_size * 512))" "$_memstick_slice_img"
|
||||
dd if="$MEMSTICK" of="$_memstick_slice_img" bs=512 skip="$_slice_start" conv=sparse status=none
|
||||
|
||||
MD_SLICE=$(mdconfig -a -t vnode -f "$_memstick_slice_img")
|
||||
_ufs_meta=$(
|
||||
bsdlabel "/dev/${MD_SLICE}" 2>/dev/null \
|
||||
| awk '$1 == "a:" { print $2 " " $3; exit }'
|
||||
)
|
||||
_ufs_size=$(echo "$_ufs_meta" | awk '{print $1}')
|
||||
_ufs_offset=$(echo "$_ufs_meta" | awk '{print $2}')
|
||||
if [ -z "${_ufs_size:-}" ] || [ -z "${_ufs_offset:-}" ]; then
|
||||
echo "ERROR: could not determine UFS root partition offset in ${MEMSTICK}"
|
||||
mdconfig -d -u "${MD_SLICE}" 2>/dev/null || true
|
||||
mdconfig -d -u "${MD_SRC}" 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
truncate -s "$((_ufs_size * 512))" "$_memstick_ufs_img"
|
||||
dd if="$_memstick_slice_img" of="$_memstick_ufs_img" bs=512 skip="$_ufs_offset" conv=sparse status=none
|
||||
|
||||
MD_ROOTFS=$(mdconfig -a -t vnode -f "$_memstick_ufs_img")
|
||||
mount -r -t ufs "/dev/${MD_ROOTFS}" "$_memstick_mount"
|
||||
}
|
||||
|
||||
cleanup_memstick_rootfs() {
|
||||
_memstick_mount="$1"
|
||||
|
||||
umount "$_memstick_mount" 2>/dev/null || true
|
||||
[ -n "${MD_ROOTFS:-}" ] && mdconfig -d -u "${MD_ROOTFS}" 2>/dev/null || true
|
||||
[ -n "${MD_SLICE:-}" ] && mdconfig -d -u "${MD_SLICE}" 2>/dev/null || true
|
||||
[ -n "${MD_SRC:-}" ] && mdconfig -d -u "${MD_SRC}" 2>/dev/null || true
|
||||
rm -f "${CACHE_DIR}/memstick-freebsd-slice.img" "${CACHE_DIR}/memstick-rootfs.img"
|
||||
MD_ROOTFS=""
|
||||
MD_SLICE=""
|
||||
MD_SRC=""
|
||||
}
|
||||
|
||||
verify_memstick_cache() {
|
||||
if [ ! -f "$MEMSTICK" ] || [ ! -f "${MEMSTICK}.SHA256" ]; then
|
||||
return 1
|
||||
fi
|
||||
_expected_sha=$(
|
||||
awk -v image="$(basename "$MEMSTICK")" '
|
||||
$2 == "(" image ")" { print $4; exit }
|
||||
' "${MEMSTICK}.SHA256"
|
||||
)
|
||||
[ -n "${_expected_sha:-}" ] || return 1
|
||||
[ "$(/sbin/sha256 -q "$MEMSTICK")" = "$_expected_sha" ]
|
||||
}
|
||||
|
||||
install_image_bootcode() {
|
||||
_image_md="$1"
|
||||
_image_root="$2"
|
||||
|
||||
if [ ! -f "${_image_root}/boot/mbr" ] || [ ! -f "${_image_root}/boot/boot" ]; then
|
||||
echo "ERROR: missing bootcode files in ${_image_root}/boot"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
gpart bootcode -b "${_image_root}/boot/mbr" "/dev/${_image_md}"
|
||||
gpart bootcode -b "${_image_root}/boot/boot" "/dev/${_image_md}s1"
|
||||
}
|
||||
|
||||
build_live_qml_installer() {
|
||||
QML_BUILD_DIR="${CACHE_DIR}/qml-installer-build"
|
||||
QML_SOURCE_DIR="${SCRIPT_DIR}/firstboot/gui/qml-installer"
|
||||
QML_INSTALLER_BIN="${CACHE_DIR}/clawdie-qml-installer"
|
||||
|
||||
if ! command -v qmake6 >/dev/null 2>&1; then
|
||||
echo "ERROR: qmake6 not found on build host."
|
||||
echo "Install Qt6 build tools, then rerun build.sh."
|
||||
echo "Example (FreeBSD): sudo pkg install -y qt6-base qt6-declarative qt6-buildtools"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> [5b/7] Building live QML installer..."
|
||||
rm -rf "$QML_BUILD_DIR"
|
||||
mkdir -p "$QML_BUILD_DIR"
|
||||
|
||||
(
|
||||
cd "$QML_BUILD_DIR"
|
||||
qmake6 "${QML_SOURCE_DIR}/qml-installer.pro"
|
||||
make
|
||||
)
|
||||
|
||||
cp "${QML_BUILD_DIR}/clawdie-qml-installer" "$QML_INSTALLER_BIN"
|
||||
chmod +x "$QML_INSTALLER_BIN"
|
||||
}
|
||||
|
||||
install_live_runtime_packages() {
|
||||
echo " Installing live GUI runtime packages into image..."
|
||||
|
||||
_pkg_files=""
|
||||
for _pkg in $(pkg_list_live_installer); do
|
||||
_archive=$(pkg_archive_for "$_pkg")
|
||||
if [ -z "${_archive:-}" ]; then
|
||||
echo "ERROR: missing package archive for ${_pkg}"
|
||||
exit 1
|
||||
fi
|
||||
_pkg_files="${_pkg_files} ${_archive}"
|
||||
done
|
||||
|
||||
mkdir -p "${MOUNT_POINT}/dev" "${MOUNT_POINT}/proc"
|
||||
_mounted_devfs=0
|
||||
_mounted_procfs=0
|
||||
|
||||
if mount -t devfs devfs "${MOUNT_POINT}/dev"; then
|
||||
_mounted_devfs=1
|
||||
fi
|
||||
if mount -t procfs proc "${MOUNT_POINT}/proc"; then
|
||||
_mounted_procfs=1
|
||||
fi
|
||||
|
||||
if ! env ASSUME_ALWAYS_YES=yes HANDLE_RC_SCRIPTS=no \
|
||||
/usr/local/sbin/pkg-static -o PKG_TRIGGERS_ENABLE=false -r "$MOUNT_POINT" add -f ${_pkg_files}; then
|
||||
[ "$_mounted_procfs" -eq 1 ] && umount "${MOUNT_POINT}/proc" 2>/dev/null || true
|
||||
[ "$_mounted_devfs" -eq 1 ] && umount "${MOUNT_POINT}/dev" 2>/dev/null || true
|
||||
echo "ERROR: failed to install live GUI runtime packages into image"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ "$_mounted_procfs" -eq 1 ] && umount "${MOUNT_POINT}/proc" 2>/dev/null || true
|
||||
[ "$_mounted_devfs" -eq 1 ] && umount "${MOUNT_POINT}/dev" 2>/dev/null || true
|
||||
}
|
||||
|
||||
configure_live_installer_session() {
|
||||
echo " Configuring live installer session..."
|
||||
|
||||
mkdir -p "${MOUNT_POINT}/usr/local/bin"
|
||||
install -m 0755 "${CACHE_DIR}/clawdie-qml-installer" \
|
||||
"${MOUNT_POINT}/usr/local/bin/clawdie-qml-installer"
|
||||
install -m 0755 "${LIVE_SESSION_DIR}/clawdie-live-installer-launch.sh" \
|
||||
"${MOUNT_POINT}/usr/local/bin/clawdie-live-installer-launch.sh"
|
||||
|
||||
mkdir -p "${MOUNT_POINT}/usr/local/etc/lightdm/lightdm.conf.d"
|
||||
install -m 0644 "${LIVE_SESSION_DIR}/lightdm-live.conf" \
|
||||
"${MOUNT_POINT}/usr/local/etc/lightdm/lightdm.conf.d/50-clawdie-live.conf"
|
||||
|
||||
if ! /usr/sbin/pw -R "$MOUNT_POINT" usershow clawdie-installer >/dev/null 2>&1; then
|
||||
/usr/sbin/pw -R "$MOUNT_POINT" useradd clawdie-installer \
|
||||
-m \
|
||||
-s /bin/sh \
|
||||
-c "Clawdie Live Installer"
|
||||
fi
|
||||
|
||||
mkdir -p "${MOUNT_POINT}/home/clawdie-installer"
|
||||
install -m 0755 "${LIVE_SESSION_DIR}/xprofile" \
|
||||
"${MOUNT_POINT}/home/clawdie-installer/.xprofile"
|
||||
cat > "${MOUNT_POINT}/home/clawdie-installer/.dmrc" <<'EOF'
|
||||
[Desktop]
|
||||
Session=lumina
|
||||
EOF
|
||||
chroot "$MOUNT_POINT" chown -R clawdie-installer:clawdie-installer /home/clawdie-installer
|
||||
|
||||
set_config_line "${MOUNT_POINT}/etc/rc.conf" 'dbus_enable="YES"'
|
||||
set_config_line "${MOUNT_POINT}/etc/rc.conf" 'seatd_enable="YES"'
|
||||
set_config_line "${MOUNT_POINT}/etc/rc.conf" 'lightdm_enable="YES"'
|
||||
set_config_line "${MOUNT_POINT}/etc/rc.conf" 'display_manager="lightdm"'
|
||||
}
|
||||
|
||||
# --- step 1: fetch FreeBSD memstick ---
|
||||
MEMSTICK="${CACHE_DIR}/FreeBSD-${FREEBSD_VERSION}-${FREEBSD_ARCH}-memstick.img"
|
||||
if [ "$SKIP_FETCH" -eq 0 ] || [ ! -f "$MEMSTICK" ]; then
|
||||
|
|
@ -107,8 +329,13 @@ if [ "$SKIP_FETCH" -eq 0 ] || [ ! -f "$MEMSTICK" ]; then
|
|||
mkdir -p "$CACHE_DIR"
|
||||
curl -L --progress-bar -o "$MEMSTICK" "$FREEBSD_MEMSTICK_URL"
|
||||
curl -L -o "${MEMSTICK}.SHA256" "$FREEBSD_MEMSTICK_SHA256_URL"
|
||||
sha256 -c "${MEMSTICK}.SHA256" || { echo "ERROR: checksum mismatch on memstick"; exit 1; }
|
||||
verify_memstick_cache || { echo "ERROR: checksum mismatch on memstick"; exit 1; }
|
||||
else
|
||||
if ! verify_memstick_cache; then
|
||||
echo "ERROR: cached FreeBSD memstick failed checksum verification."
|
||||
echo "Remove ${MEMSTICK} and rerun without --skip-fetch."
|
||||
exit 1
|
||||
fi
|
||||
echo "==> [1/7] FreeBSD memstick cached."
|
||||
fi
|
||||
|
||||
|
|
@ -239,7 +466,14 @@ if [ "$SKIP_FETCH" -eq 0 ] || [ ! -f "$CLAWDIE_TARBALL_ISO" ]; then
|
|||
|
||||
(
|
||||
cd "$AI_SRC_DIR"
|
||||
npm ci --no-audit --no-fund
|
||||
if ! npm ci --no-audit --no-fund; then
|
||||
echo " WARN: npm ci failed for Clawdie-AI v${CLAWDIE_VERSION}; falling back to npm install."
|
||||
echo " WARN: This usually means the published release tarball is out of sync with package-lock.json."
|
||||
if ! npm install --no-audit --no-fund; then
|
||||
echo " WARN: npm install failed due to dependency resolution; retrying with --legacy-peer-deps."
|
||||
npm install --no-audit --no-fund --legacy-peer-deps
|
||||
fi
|
||||
fi
|
||||
)
|
||||
|
||||
mv "$AI_SRC_DIR" "${STAGE_AI_DIR}/Clawdie-AI"
|
||||
|
|
@ -294,18 +528,21 @@ if [ ! -f "$WORK_IMG" ]; then
|
|||
# Mount memstick read-only to extract base system
|
||||
MEMSTICK_MNT="${CACHE_DIR}/memstick-src"
|
||||
mkdir -p "$MEMSTICK_MNT"
|
||||
MD_SRC=$(mdconfig -a -t vnode -f "$MEMSTICK")
|
||||
mount -r -t ufs /dev/${MD_SRC}s2a "$MEMSTICK_MNT"
|
||||
mount_memstick_rootfs "$MEMSTICK_MNT"
|
||||
echo " Copying base system from memstick..."
|
||||
|
||||
# Copy all files from memstick to new image (excluding package cache)
|
||||
tar -C "$MEMSTICK_MNT" -cf - . | tar -C "$MOUNT_POINT" -xf -
|
||||
(
|
||||
cd "$MEMSTICK_MNT"
|
||||
pax -rw -pe . "$MOUNT_POINT"
|
||||
)
|
||||
|
||||
# Cleanup memstick mount
|
||||
umount "$MEMSTICK_MNT"
|
||||
mdconfig -d -u ${MD_SRC}
|
||||
cleanup_memstick_rootfs "$MEMSTICK_MNT"
|
||||
rm -rf "$MEMSTICK_MNT"
|
||||
|
||||
install_image_bootcode "$MD" "$MOUNT_POINT"
|
||||
|
||||
# Store MD device for later cleanup
|
||||
echo "$MD" > "${CACHE_DIR}/.md_device"
|
||||
else
|
||||
|
|
@ -323,14 +560,17 @@ else
|
|||
echo " Extracting base system from memstick..."
|
||||
MEMSTICK_MNT="${CACHE_DIR}/memstick-src"
|
||||
mkdir -p "$MEMSTICK_MNT"
|
||||
MD_SRC=$(mdconfig -a -t vnode -f "$MEMSTICK")
|
||||
mount -r -t ufs /dev/${MD_SRC}s2a "$MEMSTICK_MNT"
|
||||
mount_memstick_rootfs "$MEMSTICK_MNT"
|
||||
|
||||
tar -C "$MEMSTICK_MNT" -cf - . | tar -C "$MOUNT_POINT" -xf -
|
||||
(
|
||||
cd "$MEMSTICK_MNT"
|
||||
pax -rw -pe . "$MOUNT_POINT"
|
||||
)
|
||||
|
||||
umount "$MEMSTICK_MNT"
|
||||
mdconfig -d -u ${MD_SRC}
|
||||
cleanup_memstick_rootfs "$MEMSTICK_MNT"
|
||||
rm -rf "$MEMSTICK_MNT"
|
||||
|
||||
install_image_bootcode "$MD" "$MOUNT_POINT"
|
||||
fi
|
||||
|
||||
# Store MD device for later cleanup
|
||||
|
|
@ -340,12 +580,22 @@ fi
|
|||
# --- step 6: inject payload ---
|
||||
echo "==> [6/7] Injecting payload..."
|
||||
|
||||
build_live_qml_installer
|
||||
|
||||
# Create share directory on USB
|
||||
USB_SHARE="${MOUNT_POINT}/usr/local/share/clawdie-iso"
|
||||
mkdir -p "$USB_SHARE"
|
||||
|
||||
# Step 1 switches the live boot entrypoint away from auto-running
|
||||
# /etc/installerconfig. Keep the script in USB_SHARE for later explicit
|
||||
# bsdinstall invocation, but remove any legacy boot-time auto script.
|
||||
rm -f "${MOUNT_POINT}/etc/installerconfig"
|
||||
|
||||
install_live_runtime_packages
|
||||
configure_live_installer_session
|
||||
|
||||
# Copy payload
|
||||
cp "${SCRIPT_DIR}/installerconfig" "${MOUNT_POINT}/etc/installerconfig"
|
||||
cp "${SCRIPT_DIR}/installerconfig" "${USB_SHARE}/installerconfig"
|
||||
cp -r "${SCRIPT_DIR}/firstboot" "${USB_SHARE}/"
|
||||
cp -r "${PKG_REPO_DIR}" "${USB_SHARE}/"
|
||||
if [ -d "$NPM_GLOBALS_DIR" ]; then
|
||||
|
|
|
|||
|
|
@ -138,10 +138,9 @@ during baremetal install.
|
|||
|
||||
Phase 1 validation should be narrow and practical:
|
||||
|
||||
- LLM key ping: validate only providers for which the operator actually entered
|
||||
a key.
|
||||
- Telegram test: validate bot token format and optionally send a test message.
|
||||
- Disk selection: display model, size, and minimum capacity warning.
|
||||
- Tailscale auth key: validate format only when the operator entered one.
|
||||
- SSH public key: validate basic key shape when the operator entered one.
|
||||
- If the live environment has no working network, validation should be
|
||||
skippable with a warning rather than a hard block.
|
||||
|
||||
|
|
@ -176,7 +175,7 @@ This replaces the current overloading of `/tmp/clawdie-install.conf` as both UI
|
|||
contract and install execution input.
|
||||
|
||||
This also avoids broadening the current `/tmp` exemption in `AGENTS.md`, which
|
||||
is intentionally limited to the legacy GUI-firstboot handoff and progress files.
|
||||
is intentionally limited to the current GUI-firstboot handoff and progress files.
|
||||
|
||||
### 5. Commit step
|
||||
|
||||
|
|
|
|||
|
|
@ -233,16 +233,6 @@ fi
|
|||
SSH_PUBLIC_KEY=$(_dialog --inputbox \
|
||||
"SSH public key (optional — paste ssh-ed25519 or ssh-rsa):" 12 70 "")
|
||||
|
||||
ANTHROPIC_API_KEY=$(_dialog --passwordbox \
|
||||
"Anthropic API Key (optional).\n\n" \
|
||||
"Get from: console.anthropic.com\n" \
|
||||
"Leave blank to configure later." 12 70 "")
|
||||
|
||||
CLAUDE_CODE_OAUTH_TOKEN=$(_dialog --passwordbox \
|
||||
"Claude Code OAuth Token (optional).\n\n" \
|
||||
"Run 'claude setup-token' elsewhere, paste token here.\n" \
|
||||
"Leave blank to configure later." 12 70 "")
|
||||
|
||||
# Defaults: all jails enabled, no local LLM (can be enabled post-install)
|
||||
: "${AGENT_GENDER:=f}"
|
||||
FEATURE_GIT="YES"
|
||||
|
|
@ -261,8 +251,6 @@ fi
|
|||
SUMMARY_MSG+="Locale: ${SYSTEM_LOCALE}\n"
|
||||
SUMMARY_MSG+="Keymap: ${KEYMAP}\n"
|
||||
SUMMARY_MSG+="SSH key: $([ -n "$SSH_PUBLIC_KEY" ] && echo "✓ Provided" || echo "✗ None")\n"
|
||||
SUMMARY_MSG+="Claude API: $([ -n "$ANTHROPIC_API_KEY" ] && echo "✓ Provided" || echo "✗ None")\n"
|
||||
SUMMARY_MSG+="Claude OAuth: $([ -n "$CLAUDE_CODE_OAUTH_TOKEN" ] && echo "✓ Provided" || echo "✗ None")\n"
|
||||
if [ "${FEATURE_TAILSCALE}" = "YES" ]; then
|
||||
if [ -n "$TAILSCALE_AUTHKEY" ]; then
|
||||
SUMMARY_MSG+="Tailscale: ✓ Enabled (auth key provided)\n"
|
||||
|
|
@ -272,6 +260,8 @@ fi
|
|||
else
|
||||
SUMMARY_MSG+="Tailscale: ✗ Disabled (SSH on public port 22)\n"
|
||||
fi
|
||||
SUMMARY_MSG+="Provider keys: configure after first boot in the controlplane\n"
|
||||
SUMMARY_MSG+="Telegram: configure after first boot in the controlplane\n"
|
||||
SUMMARY_MSG+="\nProceed with installation?"
|
||||
|
||||
if ! _dialog --yesno "$SUMMARY_MSG" 16 70; then
|
||||
|
|
@ -284,12 +274,9 @@ fi
|
|||
|
||||
export CLAWDIE_BOOT_MODE POOL_NAME
|
||||
export ASSISTANT_NAME AGENT_GENDER AGENT_DOMAIN TZ SSH_PUBLIC_KEY
|
||||
export HOSTNAME INSTALL_MODE PROFILE OPENROUTER_API_KEY TELEGRAM_ADMIN_ID TELEGRAM_ADMIN_IDS
|
||||
export HOSTNAME INSTALL_MODE PROFILE
|
||||
export SYSTEM_LOCALE DISPLAY_LOCALE ASSISTANT_LOCALE KEYMAP
|
||||
export PI_TUI_PROVIDER PI_TUI_MODEL ZAI_API_KEY OPENROUTER_API_KEY ANTHROPIC_API_KEY
|
||||
export CLAUDE_CODE_OAUTH_TOKEN
|
||||
export EMBED_BASE_URL EMBED_MODEL EMBED_API_KEY EMBED_DIMENSIONS
|
||||
export TELEGRAM_BOT_TOKEN TELEGRAM_ADMIN_IDS FEATURE_TELEGRAM
|
||||
export FEATURE_TAILSCALE TAILSCALE_AUTHKEY
|
||||
export CODE_HOSTING_MODE FEATURE_GIT FEATURE_GITEA FORGEJO_DISK_ESTIMATE
|
||||
export LOCAL_LLM_PROVIDER FEATURE_OLLAMA FEATURE_LLAMA_CPP FEATURE_OLLAMA_HPP
|
||||
|
|
|
|||
|
|
@ -299,8 +299,6 @@ class InstallerBackend : public QObject {
|
|||
Q_PROPERTY(bool installNvidia READ installNvidia WRITE setInstallNvidia NOTIFY installNvidiaChanged)
|
||||
Q_PROPERTY(bool installLLM READ installLLM WRITE setInstallLLM NOTIFY installLLMChanged)
|
||||
Q_PROPERTY(bool installationStarted READ installationStarted NOTIFY installationStartedChanged)
|
||||
Q_PROPERTY(QString anthropicApiKey READ anthropicApiKey WRITE setAnthropicApiKey NOTIFY anthropicApiKeyChanged)
|
||||
Q_PROPERTY(QString claudeOAuthToken READ claudeOAuthToken WRITE setClaudeOAuthToken NOTIFY claudeOAuthTokenChanged)
|
||||
|
||||
public:
|
||||
InstallerBackend(QObject *parent = nullptr) : QObject(parent) {}
|
||||
|
|
@ -387,22 +385,6 @@ public:
|
|||
|
||||
bool installationStarted() const { return m_installationStarted; }
|
||||
|
||||
QString anthropicApiKey() const { return m_anthropicApiKey; }
|
||||
void setAnthropicApiKey(const QString &key) {
|
||||
if (key != m_anthropicApiKey) {
|
||||
m_anthropicApiKey = key;
|
||||
emit anthropicApiKeyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString claudeOAuthToken() const { return m_claudeOAuthToken; }
|
||||
void setClaudeOAuthToken(const QString &token) {
|
||||
if (token != m_claudeOAuthToken) {
|
||||
m_claudeOAuthToken = token;
|
||||
emit claudeOAuthTokenChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void goNext() {
|
||||
if (m_currentPage < 7)
|
||||
setCurrentPage(m_currentPage + 1);
|
||||
|
|
@ -417,6 +399,28 @@ public:
|
|||
if (m_installationStarted)
|
||||
return false;
|
||||
|
||||
if (qEnvironmentVariableIsSet("CLAWDIE_LIVE_SESSION")) {
|
||||
QFile logFile("/var/log/clawdie-firstboot.log");
|
||||
if (logFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream log(&logFile);
|
||||
log << "[live-installer] Live GUI session bootstrapped successfully.\n";
|
||||
log << "[live-installer] Commit path is not implemented in this build yet.\n";
|
||||
log << "[live-installer] Stop here and continue with Step 2/3 implementation.\n";
|
||||
logFile.close();
|
||||
}
|
||||
|
||||
QFile progressFile("/var/log/clawdie-firstboot.progress");
|
||||
if (progressFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream progress(&progressFile);
|
||||
progress << "ERROR=live-session-bootstrap-only\n";
|
||||
progressFile.close();
|
||||
}
|
||||
|
||||
m_installationStarted = true;
|
||||
emit installationStartedChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
QFile configFile("/tmp/clawdie-install.conf");
|
||||
if (!configFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
qWarning() << "Failed to create config file:" << configFile.errorString();
|
||||
|
|
@ -430,7 +434,7 @@ public:
|
|||
out << "# User settings\n";
|
||||
out << "ASSISTANT_NAME=\"" << m_username << "\"\n";
|
||||
out << "AGENT_DOMAIN=\"" << m_username.toLower() << ".home.arpa\"\n";
|
||||
out << "CLAWDIE_PASSWORD=\"" << m_password << "\"\n\n";
|
||||
out << "CLAWDIE_USER_PASSWORD=\"" << m_password << "\"\n\n";
|
||||
|
||||
out << "# Installation settings\n";
|
||||
out << "INSTALL_DISK=\"" << m_selectedDisk << "\"\n";
|
||||
|
|
@ -453,10 +457,7 @@ public:
|
|||
out << "TAILSCALE_AUTHKEY=\"\"\n";
|
||||
out << "FEATURE_GIT=\"YES\"\n";
|
||||
out << "FEATURE_GITEA=\"NO\"\n";
|
||||
out << "CODE_HOSTING_MODE=\"git\"\n\n";
|
||||
out << "# Claude authentication\n";
|
||||
out << "ANTHROPIC_API_KEY=\"" << m_anthropicApiKey << "\"\n";
|
||||
out << "CLAUDE_CODE_OAUTH_TOKEN=\"" << m_claudeOAuthToken << "\"\n";
|
||||
out << "CODE_HOSTING_MODE=\"git\"\n";
|
||||
|
||||
configFile.close();
|
||||
|
||||
|
|
@ -509,8 +510,6 @@ public:
|
|||
void installNvidiaChanged();
|
||||
void installLLMChanged();
|
||||
void installationStartedChanged();
|
||||
void anthropicApiKeyChanged();
|
||||
void claudeOAuthTokenChanged();
|
||||
|
||||
private:
|
||||
int m_currentPage = 0;
|
||||
|
|
@ -524,8 +523,6 @@ private:
|
|||
bool m_installNvidia = true;
|
||||
bool m_installLLM = false;
|
||||
bool m_installationStarted = false;
|
||||
QString m_anthropicApiKey;
|
||||
QString m_claudeOAuthToken;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ ColumnLayout {
|
|||
}
|
||||
|
||||
Text {
|
||||
text: tracker.success ? "You can now log in with the credentials you created." : "You may retry the installation or seek support."
|
||||
text: tracker.success ? "Finish machine bootstrap first. Provider keys, Telegram, and browser sign-in are configured after boot." : "You may retry the installation or seek support."
|
||||
font.pixelSize: 12
|
||||
color: "#666666"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ ColumnLayout {
|
|||
|
||||
// Title
|
||||
Text {
|
||||
text: "Create User Account"
|
||||
text: "Identity and Access"
|
||||
font.pixelSize: 24
|
||||
font.bold: true
|
||||
color: "#333333"
|
||||
|
|
@ -15,7 +15,7 @@ ColumnLayout {
|
|||
|
||||
// Instructions
|
||||
Text {
|
||||
text: "Set up the primary user account for your Clawdie AI system."
|
||||
text: "Set the assistant name and the initial local password for the clawdie account. Provider keys, Telegram, and site logins are configured after first boot in the controlplane."
|
||||
font.pixelSize: 13
|
||||
color: "#666666"
|
||||
wrapMode: Text.WordWrap
|
||||
|
|
@ -41,7 +41,7 @@ ColumnLayout {
|
|||
spacing: 5
|
||||
|
||||
Text {
|
||||
text: "Username"
|
||||
text: "Assistant Name"
|
||||
font.pixelSize: 13
|
||||
font.bold: true
|
||||
color: "#333333"
|
||||
|
|
@ -51,7 +51,7 @@ ColumnLayout {
|
|||
id: usernameField
|
||||
Layout.fillWidth: true
|
||||
text: backend.username
|
||||
placeholderText: "clawdie"
|
||||
placeholderText: "Clawdie"
|
||||
font.pixelSize: 13
|
||||
|
||||
onEditingFinished: {
|
||||
|
|
@ -113,77 +113,6 @@ ColumnLayout {
|
|||
}
|
||||
}
|
||||
|
||||
// Separator
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
color: "#eeeeee"
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Claude Authentication (optional)"
|
||||
font.pixelSize: 13
|
||||
font.bold: true
|
||||
color: "#666666"
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Provide at least one to enable Claude Code on first boot."
|
||||
font.pixelSize: 11
|
||||
color: "#999999"
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
// Anthropic API Key
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 5
|
||||
|
||||
Text {
|
||||
text: "Anthropic API Key"
|
||||
font.pixelSize: 13
|
||||
font.bold: true
|
||||
color: "#333333"
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: anthropicKeyField
|
||||
Layout.fillWidth: true
|
||||
placeholderText: "sk-ant-..."
|
||||
echoMode: TextField.Password
|
||||
font.pixelSize: 13
|
||||
|
||||
onEditingFinished: {
|
||||
backend.anthropicApiKey = text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Claude Code OAuth Token
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 5
|
||||
|
||||
Text {
|
||||
text: "Claude Code OAuth Token"
|
||||
font.pixelSize: 13
|
||||
font.bold: true
|
||||
color: "#333333"
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: claudeOAuthField
|
||||
Layout.fillWidth: true
|
||||
placeholderText: "Run 'claude setup-token' elsewhere"
|
||||
echoMode: TextField.Password
|
||||
font.pixelSize: 13
|
||||
|
||||
onEditingFinished: {
|
||||
backend.claudeOAuthToken = text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ cat > /tmp/test-clawdie-install.conf << 'EOF'
|
|||
# User settings
|
||||
ASSISTANT_NAME="testuser"
|
||||
AGENT_DOMAIN="testuser.home.arpa"
|
||||
CLAWDIE_PASSWORD="testpass123"
|
||||
CLAWDIE_USER_PASSWORD="testpass123"
|
||||
|
||||
# Installation settings
|
||||
INSTALL_DISK="da0"
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ cd "$TESTDIR"
|
|||
# Setup test environment
|
||||
mkdir -p "$TESTDIR/etc/pkg/repos"
|
||||
mkdir -p "$TESTDIR/etc/profile.d"
|
||||
mkdir -p "$TESTDIR/boot"
|
||||
mkdir -p "$TESTDIR/var/log"
|
||||
mkdir -p "$TESTDIR/var/cache/pkg/bastille"
|
||||
mkdir -p "$TESTDIR/mnt/media/packages"
|
||||
|
|
@ -55,6 +56,8 @@ export CLAWDIE_USB_REPO_CONF="$PKG_CONF_DIR/Clawdie-USB.conf"
|
|||
export USB_PKG_PATH="$TESTDIR/mnt/media/packages"
|
||||
export BASTILLE_PKG_CACHE="$TESTDIR/var/cache/pkg/bastille"
|
||||
export RC_CONF="$TESTDIR/etc/rc.conf"
|
||||
export LOADER_CONF="$TESTDIR/boot/loader.conf"
|
||||
export SYSCTL_CONF="$TESTDIR/etc/sysctl.conf"
|
||||
export HOSTNAME_FILE="$TESTDIR/etc/hostname"
|
||||
export PROFILE_DIR="$TESTDIR/etc/profile.d"
|
||||
export LOG_FILE="$TESTDIR/var/log/integration.log"
|
||||
|
|
@ -76,7 +79,7 @@ export KEYMAP="sl.kbd"
|
|||
export DETECTED_GPU="intel"
|
||||
|
||||
# Init
|
||||
touch "$LOG_FILE" "$PROGRESS_FILE" "$RC_CONF"
|
||||
touch "$LOG_FILE" "$PROGRESS_FILE" "$RC_CONF" "$LOADER_CONF" "$SYSCTL_CONF"
|
||||
|
||||
echo ""
|
||||
echo "╔════════════════════════════════════════════════════════════════╗"
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ clawdie_setup_import_parse_file() {
|
|||
_value=$(printf '%s' "$_value" | sed 's/^"//; s/"$//; s/^'\''//; s/'\''$//')
|
||||
|
||||
case "$_key" in
|
||||
SETUP_SCHEMA_VERSION|ISO_RELEASE|ISO_GIT_COMMIT|ZAI_API_KEY|ZAI_API_BASE|OPENROUTER_API_KEY|OPENAI_API_KEY|ANTHROPIC_API_KEY|CLAUDE_CODE_OAUTH_TOKEN|TELEGRAM_BOT_TOKEN|TELEGRAM_ADMIN_ID|INSTALL_MODE|ASSISTANT_NAME|PROFILE|TIMEZONE|HOSTNAME|ZFS_POOL|ZFS_LAYOUT|ZFS_DATA_DISKS|ZFS_HOT_SPARES|ZFS_PREFIX|OPERATOR_EMAIL|OPERATOR_PASSWORD|SSH_AUTHORIZED_KEY|CLAWDIE_USER_PASSWORD|SYSTEM_LOCALE|KEYMAP)
|
||||
SETUP_SCHEMA_VERSION|ISO_RELEASE|ISO_GIT_COMMIT|INSTALL_MODE|ASSISTANT_NAME|AGENT_DOMAIN|PROFILE|TIMEZONE|HOSTNAME|ZFS_POOL|ZFS_LAYOUT|ZFS_DATA_DISKS|ZFS_HOT_SPARES|ZFS_PREFIX|OPERATOR_EMAIL|OPERATOR_PASSWORD|SSH_PUBLIC_KEY|SSH_AUTHORIZED_KEY|CLAWDIE_USER_PASSWORD|SYSTEM_LOCALE|KEYMAP|TAILSCALE_AUTHKEY)
|
||||
eval "$_key=\$_value"
|
||||
export "$_key"
|
||||
;;
|
||||
|
|
@ -148,28 +148,9 @@ clawdie_setup_import_apply_defaults() {
|
|||
ASSISTANT_LOCALE="${ASSISTANT_LOCALE:-$SYSTEM_LOCALE}"
|
||||
KEYMAP="${KEYMAP:-us}"
|
||||
|
||||
if [ -n "${TELEGRAM_ADMIN_ID:-}" ] && [ -z "${TELEGRAM_ADMIN_IDS:-}" ]; then
|
||||
TELEGRAM_ADMIN_IDS="$TELEGRAM_ADMIN_ID"
|
||||
if [ -n "${SSH_AUTHORIZED_KEY:-}" ] && [ -z "${SSH_PUBLIC_KEY:-}" ]; then
|
||||
SSH_PUBLIC_KEY="$SSH_AUTHORIZED_KEY"
|
||||
fi
|
||||
if [ -n "${TELEGRAM_BOT_TOKEN:-}" ]; then
|
||||
FEATURE_TELEGRAM="${FEATURE_TELEGRAM:-YES}"
|
||||
fi
|
||||
if [ -n "${ZAI_API_KEY:-}" ]; then
|
||||
PI_TUI_PROVIDER="${PI_TUI_PROVIDER:-zai}"
|
||||
PI_TUI_MODEL="${PI_TUI_MODEL:-glm-5}"
|
||||
fi
|
||||
if [ -n "${OPENROUTER_API_KEY:-}" ]; then
|
||||
PI_TUI_PROVIDER="${PI_TUI_PROVIDER:-openrouter}"
|
||||
PI_TUI_MODEL="${PI_TUI_MODEL:-openai/o3}"
|
||||
fi
|
||||
if [ -n "${OPENAI_API_KEY:-}" ]; then
|
||||
: "${PI_TUI_PROVIDER:=openai}"
|
||||
fi
|
||||
if [ -n "${ANTHROPIC_API_KEY:-}" ]; then
|
||||
: "${PI_TUI_PROVIDER:=anthropic}"
|
||||
fi
|
||||
PI_TUI_PROVIDER="${PI_TUI_PROVIDER:-zai}"
|
||||
PI_TUI_MODEL="${PI_TUI_MODEL:-glm-5}"
|
||||
if [ -n "${TAILSCALE_AUTHKEY:-}" ]; then
|
||||
FEATURE_TAILSCALE="${FEATURE_TAILSCALE:-YES}"
|
||||
fi
|
||||
|
|
@ -195,8 +176,7 @@ clawdie_setup_import_apply_defaults() {
|
|||
esac
|
||||
|
||||
export TZ HOSTNAME AGENT_DOMAIN SYSTEM_LOCALE DISPLAY_LOCALE ASSISTANT_LOCALE KEYMAP
|
||||
export TELEGRAM_ADMIN_IDS FEATURE_TELEGRAM FEATURE_TAILSCALE
|
||||
export PI_TUI_PROVIDER PI_TUI_MODEL
|
||||
export SSH_PUBLIC_KEY FEATURE_TAILSCALE
|
||||
export POOL_NAME CLAWDIE_BOOT_MODE CLAWDIE_BOOT_MODE_PRESET
|
||||
}
|
||||
|
||||
|
|
|
|||
19
live/installer-session/clawdie-live-installer-launch.sh
Executable file
19
live/installer-session/clawdie-live-installer-launch.sh
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
RUNTIME_DIR="/var/run/clawdie-installer"
|
||||
LOG_FILE="/var/log/clawdie-live-installer.log"
|
||||
INSTALLER_BIN="/usr/local/bin/clawdie-qml-installer"
|
||||
|
||||
mkdir -p "$RUNTIME_DIR"
|
||||
touch "$LOG_FILE"
|
||||
|
||||
if pgrep -fx "$INSTALLER_BIN" >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') starting live installer session" >> "$LOG_FILE"
|
||||
|
||||
export CLAWDIE_LIVE_SESSION=1
|
||||
exec "$INSTALLER_BIN" >> "$LOG_FILE" 2>&1
|
||||
11
live/installer-session/lightdm-live.conf
Normal file
11
live/installer-session/lightdm-live.conf
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[LightDM]
|
||||
logind-check-gio=false
|
||||
sessions-directory=/usr/local/share/xsessions
|
||||
|
||||
[Seat:*]
|
||||
autologin-user=clawdie-installer
|
||||
autologin-user-timeout=0
|
||||
user-session=lumina
|
||||
greeter-session=lightdm-gtk-greeter
|
||||
greeter-hide-users=false
|
||||
allow-user-switching=false
|
||||
5
live/installer-session/xprofile
Executable file
5
live/installer-session/xprofile
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
if ! pgrep -fx /usr/local/bin/clawdie-qml-installer >/dev/null 2>&1; then
|
||||
/usr/local/bin/clawdie-live-installer-launch.sh &
|
||||
fi
|
||||
|
|
@ -4,4 +4,4 @@ xf86-input-libinput
|
|||
xf86-video-intel
|
||||
drm-kmod
|
||||
dbus
|
||||
hal
|
||||
# `hal` was removed from modern FreeBSD package repos.
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ dejavu
|
|||
|
||||
# Wayland display stack (desktop installs)
|
||||
seatd
|
||||
weston
|
||||
cage
|
||||
wayvnc
|
||||
waypipe
|
||||
|
|
@ -49,4 +48,5 @@ xwayland
|
|||
# bhyve VM management (optional, included for full offline capability)
|
||||
vm-bhyve
|
||||
grub2-bhyve
|
||||
uefi-edk2-bhyve
|
||||
# Current repo package name; provides BHYVE_UEFI.fd for VM boot.
|
||||
edk2-bhyve-g202508
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ postgresql18-client
|
|||
# db-jail
|
||||
postgresql18-server
|
||||
postgresql18-contrib
|
||||
pgvector
|
||||
postgresql18-pgvector
|
||||
|
||||
# worker-jail
|
||||
cage
|
||||
|
|
@ -25,7 +25,7 @@ chromium
|
|||
|
||||
# management-jail (observability)
|
||||
victoria-metrics
|
||||
grafana10
|
||||
grafana
|
||||
|
||||
# ollama-jail (optional local inference)
|
||||
ollama
|
||||
|
|
|
|||
3
packages/pkg-list-live-installer.txt
Normal file
3
packages/pkg-list-live-installer.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Live installer runtime — needed on the USB image itself
|
||||
qt6-base
|
||||
qt6-declarative
|
||||
|
|
@ -4,9 +4,8 @@ lumina-core
|
|||
lumina-themes
|
||||
lumina-calculator
|
||||
lumina-archiver
|
||||
lumina-filemanager
|
||||
lumina-fm
|
||||
lumina-screenshot
|
||||
lumina-open
|
||||
openbox
|
||||
libxcb
|
||||
libxdg-basedir
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# NVIDIA driver 590.x (Maxwell & newer: GTX 750 Ti+, RTX 20/30/40)
|
||||
nvidia-driver-590
|
||||
# Current closest repo branch to the prior 590 target.
|
||||
nvidia-driver-580
|
||||
nvidia-settings
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@
|
|||
|
||||
nvidia-driver-390
|
||||
nvidia-driver-470
|
||||
nvidia-driver-590
|
||||
nvidia-driver-580
|
||||
nvidia-settings
|
||||
nvidia-xconfig
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue