Make BOS a complete, bootable, themed desktop OS
Install/boot reliability: - Use native Calamares initcpiocfg/initcpio + explicit grub-install (nvram + --removable) in post-install; drop the flaky native bootloader/grubcfg modules. - mount.conf: bind /proc /sys /dev (devtmpfs) /run + efivars into the chroot. - bos-copy-kernel: stage kernel + write a stock mkinitcpio preset (replace the archiso preset). Per-service systemctl enable (fixes NetworkManager et al. silently not enabling due to the all-or-nothing grub-btrfs.path name). System completeness: - greetd + tuigreet graphical login; installed pacman.conf + working mirrorlist; base CLI tools (nano, micro, vim, htop, …); amd/intel-ucode; tlp + hypridle power management; systemd-timesyncd, fstrim.timer; wpa_supplicant wifi; Zen browser (republished to the [Breadway] repo). Desktop + theming: - Native Lua Hyprland config (hyprland.lua) with curated standard binds; kitty (blur) replaces foot; awww wallpaper + pywal palette (tamed to a black base with warm accents); GTK dark mode. - Plymouth boot splash (bos theme: logo + spinner + status) via plymouthcfg. - Varela Round font; Calamares bread-palette sidebar (logo/black-region polish still pending).
This commit is contained in:
parent
787cc0e4c5
commit
f8ae8fe125
35 changed files with 787 additions and 180 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -38,3 +38,6 @@ logs/
|
|||
|
||||
# Claude Code local agent state
|
||||
.claude/
|
||||
|
||||
# Wallpaper source drop (baked copy lives in airootfs/usr/share/backgrounds)
|
||||
/Bread Background.png
|
||||
|
|
|
|||
90
build-local.sh
Executable file
90
build-local.sh
Executable file
|
|
@ -0,0 +1,90 @@
|
|||
#!/usr/bin/env bash
|
||||
# Local BOS ISO build for hermes (native Arch — no container needed).
|
||||
#
|
||||
# Builds straight from the working tree in ./iso. Two speedups vs the hestia
|
||||
# container build:
|
||||
# * runs natively (hermes is Arch; hestia needed a dockerised Arch)
|
||||
# * no 2 GB scp afterwards — the ISO lands here, where we test it
|
||||
#
|
||||
# FAST_BUILD=1 zstd squashfs instead of xz -9e: compresses many times
|
||||
# faster at the cost of a slightly larger image. Dev only.
|
||||
#
|
||||
# Usage: sudo ./build-local.sh # release-quality xz
|
||||
# sudo FAST_BUILD=1 ./build-local.sh # fast dev iteration
|
||||
set -euo pipefail
|
||||
|
||||
REPO="$(cd "$(dirname "$0")" && pwd)"
|
||||
WORK=/tmp/bos-work
|
||||
OUT="${OUT:-$REPO/out}"
|
||||
|
||||
# Build against a throwaway copy of the profile so the working tree stays clean
|
||||
# when FAST_BUILD / the registry rewrite mutate profile files.
|
||||
STAGE=/tmp/bos-iso-stage
|
||||
rm -rf "$STAGE" && cp -a "$REPO/iso" "$STAGE"
|
||||
|
||||
# The public git.breadway.dev URL is flaky/unreachable from hermes; Forgejo is
|
||||
# directly reachable over Tailscale (hestia 100.66.238.26:3002). Only rewrites
|
||||
# the staged copy, never the committed pacman.conf.
|
||||
sed -i 's#https://git.breadway.dev/api/packages/Breadway/arch/os#http://100.66.238.26:3002/api/packages/Breadway/arch/os#' "$STAGE/pacman.conf"
|
||||
|
||||
if [ "${FAST_BUILD:-0}" = "1" ]; then
|
||||
echo "=== FAST_BUILD: squashfs -> zstd level 6 ==="
|
||||
sed -i "s#^airootfs_image_tool_options=.*#airootfs_image_tool_options=('-comp' 'zstd' '-Xcompression-level' '6' '-b' '1M')#" "$STAGE/profiledef.sh"
|
||||
fi
|
||||
grep airootfs_image_tool_options "$STAGE/profiledef.sh"
|
||||
|
||||
# --- Bake this laptop's bakery-installed bread ecosystem into /etc/skel -------
|
||||
# The bread apps are managed by bakery (which fetches release binaries from
|
||||
# GitHub), not pacman. bakery needs DNS at install time, which the live/installed
|
||||
# image doesn't have — so instead of running bakery on the target, we copy the
|
||||
# exact binaries + bakery manifest this laptop already has into skel. Every user
|
||||
# created from skel (the live user and the installed user) then gets the same
|
||||
# versions `bakery list` reports here, fully offline. Copied at build time so the
|
||||
# binaries never bloat the git repo and always track the current bakery state.
|
||||
BREAD_BINS=(bakery bread breadd breadman breadbar breadbox breadbox-sync breadcrumbs breadpad)
|
||||
LAPTOP_HOME="${LAPTOP_HOME:-$(getent passwd "${SUDO_USER:-$USER}" | cut -d: -f6)}"
|
||||
BAKERY_BIN="$LAPTOP_HOME/.local/bin"
|
||||
BAKERY_STATE="$LAPTOP_HOME/.local/state/bakery"
|
||||
BAKERY_CACHE="$LAPTOP_HOME/.cache/bakery"
|
||||
SKEL="$STAGE/airootfs/etc/skel"
|
||||
echo "=== baking bakery bread ecosystem from $LAPTOP_HOME ==="
|
||||
install -d -m 0755 "$SKEL/.local/bin" "$SKEL/.local/state/bakery" "$SKEL/.cache/bakery"
|
||||
for b in "${BREAD_BINS[@]}"; do
|
||||
install -m 0755 "$BAKERY_BIN/$b" "$SKEL/.local/bin/$b"
|
||||
done
|
||||
install -m 0644 "$BAKERY_STATE/installed.json" "$SKEL/.local/state/bakery/installed.json"
|
||||
# bakery fetches its package index from dl.breadway.dev (then a GitHub fallback),
|
||||
# but falls back to a cached index when both are unreachable. With no network/DNS
|
||||
# in the live/installed image, even `bakery list` errors unless that cache exists,
|
||||
# so bake it in too — then bakery works fully offline (list/info from cache;
|
||||
# install/update still need network, as expected).
|
||||
install -m 0644 "$BAKERY_CACHE/index.json" "$SKEL/.cache/bakery/index.json"
|
||||
echo "baked: $(ls "$SKEL/.local/bin")"
|
||||
|
||||
# mkarchiso resets every airootfs file to 0644, so executables must be declared
|
||||
# in profiledef.sh's file_permissions array or they ship non-executable and the
|
||||
# exec-once launches fail with "permission denied". Inject a 0755 entry for each
|
||||
# baked binary right after the array opener (keeps the binary list in one place).
|
||||
perm_file="$(mktemp)"
|
||||
for b in "${BREAD_BINS[@]}"; do
|
||||
printf ' ["/etc/skel/.local/bin/%s"]="0:0:755"\n' "$b" >>"$perm_file"
|
||||
done
|
||||
sed -i "/^file_permissions=(/r $perm_file" "$STAGE/profiledef.sh"
|
||||
rm -f "$perm_file"
|
||||
echo "=== file_permissions after injection ==="; grep -A14 '^file_permissions=(' "$STAGE/profiledef.sh"
|
||||
|
||||
# Pin one timestamp for the whole build. Without this, mkarchiso derives the
|
||||
# boot-config UUID (%ARCHISO_UUID%) when it starts and the iso9660 volume UUID
|
||||
# when xorriso writes the image at the end — on a slow build these diverge by
|
||||
# the build duration, so the initramfs searches /dev/disk/by-uuid/<wrong-uuid>,
|
||||
# never finds the medium, and drops to a recovery shell. Fixing the epoch makes
|
||||
# both derive from the same instant (and makes builds reproducible).
|
||||
export SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(date +%s)}"
|
||||
echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH ($(date -u -d "@$SOURCE_DATE_EPOCH" +%Y-%m-%d-%H-%M-%S-00))"
|
||||
|
||||
echo "=== running mkarchiso ==="
|
||||
rm -rf "$WORK" && mkdir -p "$OUT"
|
||||
mkarchiso -v -w "$WORK" -o "$OUT" "$STAGE"
|
||||
|
||||
echo "=== RESULT ==="
|
||||
if ls -lh "$OUT"/*.iso 2>/dev/null; then echo "ISO BUILT OK -> $OUT"; else echo "ISO BUILD FAILED"; exit 1; fi
|
||||
|
|
@ -23,7 +23,7 @@ slideshow: "show.qml"
|
|||
slideshowAPI: 2
|
||||
|
||||
style:
|
||||
sidebarBackground: "#3b4252"
|
||||
sidebarText: "#eceff4"
|
||||
sidebarTextSelect: "#5e81ac"
|
||||
sidebarTextHighlight: "#eceff4"
|
||||
sidebarBackground: "#230b00"
|
||||
sidebarText: "#f1dcbd"
|
||||
sidebarTextSelect: "#EAB672"
|
||||
sidebarTextHighlight: "#ffffff"
|
||||
|
|
|
|||
23
iso/airootfs/etc/calamares/branding/bos/stylesheet.qss
Normal file
23
iso/airootfs/etc/calamares/branding/bos/stylesheet.qss
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/* BOS Calamares styling.
|
||||
*
|
||||
* The branding `style:` sidebar keys were being overridden, leaving the
|
||||
* step tabs invisible. This forces them: bread-palette sidebar with clearly
|
||||
* legible step labels. (A full installer retheme is tracked separately.)
|
||||
*/
|
||||
|
||||
/* Left sidebar / progress steps */
|
||||
#sidebarApp {
|
||||
background-color: #230b00;
|
||||
}
|
||||
|
||||
#sidebarApp QLabel {
|
||||
color: #f1dcbd;
|
||||
font-size: 11pt;
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
/* Logo at the top of the sidebar — keep aspect ratio, don't stretch */
|
||||
#logoApp {
|
||||
qproperty-alignment: AlignCenter;
|
||||
margin: 14px 8px;
|
||||
}
|
||||
|
|
@ -8,3 +8,32 @@ mountOptions:
|
|||
options: [noatime, "compress=zstd", "space_cache=v2"]
|
||||
- filesystem: vfat
|
||||
options: [umask=0077]
|
||||
|
||||
# API filesystems mounted into the target so chroot steps work. Without these
|
||||
# the chroot has no /proc or /dev and `mkinitcpio` aborts ("/proc must be
|
||||
# mounted!" / "/dev must be mounted!") and grub-install can't probe properly.
|
||||
# All are real-fs mounts (not bind) — Calamares 3.4.2 here applies fs-type mounts
|
||||
# reliably but not bind-type ones, so /dev uses a fresh devtmpfs (which still
|
||||
# exposes all device nodes). extraMountsEfi adds efivars on UEFI so grub-install
|
||||
# can write an NVRAM boot entry.
|
||||
extraMounts:
|
||||
- device: proc
|
||||
fs: proc
|
||||
mountPoint: /proc
|
||||
- device: sys
|
||||
fs: sysfs
|
||||
mountPoint: /sys
|
||||
- device: udev
|
||||
fs: devtmpfs
|
||||
mountPoint: /dev
|
||||
- device: devpts
|
||||
fs: devpts
|
||||
mountPoint: /dev/pts
|
||||
- device: tmpfs
|
||||
fs: tmpfs
|
||||
mountPoint: /run
|
||||
|
||||
extraMountsEfi:
|
||||
- device: efivarfs
|
||||
fs: efivarfs
|
||||
mountPoint: /sys/firmware/efi/efivars
|
||||
|
|
|
|||
6
iso/airootfs/etc/calamares/modules/plymouthcfg.conf
Normal file
6
iso/airootfs/etc/calamares/modules/plymouthcfg.conf
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
# Boot-splash theme for the installed system. Calamares sets this as the default
|
||||
# plymouth theme and signals initcpiocfg to add the plymouth hook to the
|
||||
# initramfs. The post-install script also enforces the hook + a quiet/splash
|
||||
# cmdline as a belt-and-suspenders.
|
||||
plymouth_theme: bos
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
---
|
||||
# Calamares defaults shellprocess to a 10-second timeout. post-install.sh runs
|
||||
# mkinitcpio, grub-install, grub-mkconfig, snapper setup and a networked bakery
|
||||
# install — minutes of work — so without a generous timeout it gets killed
|
||||
# partway (leaving /boot and the ESP half-populated → unbootable system). The
|
||||
# leading "-" keeps a non-zero exit non-fatal to the install.
|
||||
timeout: 1800
|
||||
# BOS finalization, run after the native initcpio + bootloader modules. It does
|
||||
# only fast, non-boot-critical work (live-medium cleanup, snapper, services,
|
||||
# dotfiles), so the shellprocess timeout can no longer leave the system
|
||||
# unbootable — the boot-critical steps are owned by dedicated Calamares modules.
|
||||
# A generous timeout is kept as a safety margin, and the leading "-" keeps a
|
||||
# non-zero exit non-fatal to the install.
|
||||
timeout: 600
|
||||
script:
|
||||
- "-/usr/bin/bash /etc/calamares/post-install.sh"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
#!/bin/bash
|
||||
# Runs inside the installed-system chroot (Calamares shellprocess, after the
|
||||
# bootloader step). Best-effort: a single failure must not abort the rest, so
|
||||
# we deliberately do NOT use `set -e`.
|
||||
# BOS-specific finalization, run inside the installed-system chroot (Calamares
|
||||
# shellprocess), AFTER the native initcpio module has built the initramfs. The
|
||||
# kernel (shellprocess@kernel) and initramfs (initcpio) are in place by now, so
|
||||
# this script installs GRUB and does the rest of setup. Calamares' own
|
||||
# `bootloader`/`grubcfg` modules are NOT used — in this archiso layout they leave
|
||||
# the ESP empty and abort; the explicit grub-install below is verified to boot.
|
||||
# Best-effort: do NOT use `set -e`; a single failure here must not abort the rest.
|
||||
set -uo pipefail
|
||||
|
||||
MAIN_USER="$(getent passwd 1000 | cut -d: -f1 || true)"
|
||||
|
|
@ -20,30 +24,42 @@ userdel -r liveuser 2>/dev/null || true
|
|||
passwd -l root || true
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Rebuild the initramfs for a real install — the live image ships the archiso
|
||||
# hooks, which would send the installed system into the live-boot path.
|
||||
# Boot splash (Plymouth) — BOS logo + spinner instead of kernel text. Done
|
||||
# BEFORE grub so grub.cfg picks up the new cmdline and the rebuilt initramfs.
|
||||
# All best-effort: if anything here fails the system still boots (just without
|
||||
# the splash) — the initramfs the initcpio module already built stays valid.
|
||||
# ---------------------------------------------------------------------------
|
||||
rm -f /etc/mkinitcpio.conf.d/archiso.conf
|
||||
cat >/etc/mkinitcpio.d/linux.preset <<'PRESET'
|
||||
# mkinitcpio preset file for the 'linux' package
|
||||
ALL_config="/etc/mkinitcpio.conf"
|
||||
ALL_kver="/boot/vmlinuz-linux"
|
||||
PRESETS=('default' 'fallback')
|
||||
default_image="/boot/initramfs-linux.img"
|
||||
fallback_image="/boot/initramfs-linux-fallback.img"
|
||||
fallback_options="-S autodetect"
|
||||
PRESET
|
||||
mkinitcpio -P || echo "WARN: mkinitcpio regeneration failed"
|
||||
if command -v plymouth-set-default-theme &>/dev/null; then
|
||||
# Ensure the plymouth hook is in HOOKS (plymouthcfg/initcpiocfg usually add it;
|
||||
# this is the belt). Handle both the udev and systemd initramfs styles.
|
||||
if ! grep -q 'plymouth' /etc/mkinitcpio.conf 2>/dev/null; then
|
||||
if grep -qE '^HOOKS=.*\bsystemd\b' /etc/mkinitcpio.conf; then
|
||||
sed -i 's/^\(HOOKS=.*\bsystemd\b\)/\1 sd-plymouth/' /etc/mkinitcpio.conf \
|
||||
|| echo "WARN: adding sd-plymouth hook failed"
|
||||
else
|
||||
sed -i 's/^\(HOOKS=.*\budev\b\)/\1 plymouth/' /etc/mkinitcpio.conf \
|
||||
|| echo "WARN: adding plymouth hook failed"
|
||||
fi
|
||||
fi
|
||||
# Clean boot: splash activates plymouth; hiding systemd status removes the
|
||||
# "[ OK ] Started ..." text (what looked like kernel output) even if the
|
||||
# splash itself doesn't grab the display (e.g. in some VMs).
|
||||
if ! grep -q 'splash' /etc/default/grub 2>/dev/null; then
|
||||
sed -i 's/^\(GRUB_CMDLINE_LINUX_DEFAULT="\)/\1splash quiet vt.global_cursor_default=0 systemd.show_status=false rd.systemd.show_status=false rd.udev.log_level=3 /' \
|
||||
/etc/default/grub || echo "WARN: adding splash cmdline failed"
|
||||
fi
|
||||
# Set the BOS theme and rebuild the initramfs (-R) with the plymouth hook.
|
||||
plymouth-set-default-theme -R bos || echo "WARN: plymouth-set-default-theme failed"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Install GRUB ourselves. Calamares' bootloader module runs before the kernel
|
||||
# and initramfs exist (archiso keeps them out of the squashfs; shellprocess
|
||||
# @kernel only lays vmlinuz down just beforehand), so its grub-install/config
|
||||
# leaves the ESP empty. Redo it here, now that /boot is fully populated.
|
||||
#
|
||||
# Two passes: the standard NVRAM entry, plus a --removable copy to
|
||||
# EFI/BOOT/BOOTX64.EFI so firmware that lost/never wrote an NVRAM entry (the
|
||||
# "no boot device / screen just refreshes" failure) still finds a bootloader.
|
||||
# Install GRUB (UEFI). /boot now has the kernel + initramfs, and the mount
|
||||
# module has bind-mounted /proc /sys /dev /run + efivars into this chroot, so
|
||||
# both grub-install passes and grub-mkconfig succeed.
|
||||
# 1. NVRAM entry (EFI/BOS/grubx64.efi + a firmware boot entry)
|
||||
# 2. --removable copy to EFI/BOOT/BOOTX64.EFI, so firmware that ignores/loses
|
||||
# the NVRAM entry (the "no boot device / PXE fallback" failure) still finds
|
||||
# a bootloader.
|
||||
# ---------------------------------------------------------------------------
|
||||
if command -v grub-install &>/dev/null; then
|
||||
grub-install --target=x86_64-efi --efi-directory=/boot/efi \
|
||||
|
|
@ -53,8 +69,6 @@ if command -v grub-install &>/dev/null; then
|
|||
--removable --recheck \
|
||||
|| echo "WARN: grub-install (removable) failed"
|
||||
fi
|
||||
|
||||
# Refresh GRUB so it references the kernel + rebuilt initramfs.
|
||||
if command -v grub-mkconfig &>/dev/null; then
|
||||
grub-mkconfig -o /boot/grub/grub.cfg || echo "WARN: grub-mkconfig failed"
|
||||
fi
|
||||
|
|
@ -76,22 +90,39 @@ if command -v snapper &>/dev/null; then
|
|||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# System services.
|
||||
# System services. Enable each one INDEPENDENTLY: `systemctl enable a b c`
|
||||
# resolves every unit first and enables NONE if any one can't be loaded, so a
|
||||
# single wrong/absent unit name would silently leave NetworkManager (etc.)
|
||||
# disabled. The loop isolates failures to the offending unit.
|
||||
# greetd — graphical login (shipped disabled; live uses tty autologin)
|
||||
# grub-btrfsd — regenerates GRUB snapshot entries (the unit is grub-btrfsd.service,
|
||||
# NOT grub-btrfs.path, which no longer exists)
|
||||
# ---------------------------------------------------------------------------
|
||||
systemctl enable NetworkManager bluetooth snapper-cleanup.timer grub-btrfs.path \
|
||||
|| echo "WARN: enabling some services failed"
|
||||
for unit in NetworkManager.service bluetooth.service systemd-timesyncd.service \
|
||||
tlp.service greetd.service snapper-cleanup.timer grub-btrfsd.service \
|
||||
fstrim.timer; do
|
||||
systemctl enable "$unit" || echo "WARN: failed to enable $unit"
|
||||
done
|
||||
systemctl set-default graphical.target || echo "WARN: set-default graphical failed"
|
||||
|
||||
# The bread ecosystem (bread, breadbar, breadbox, breadcrumbs, breadpad,
|
||||
# bos-settings) is baked into the squashfs and already copied onto the target by
|
||||
# unpackfs — no install step needed here, and the install works fully offline.
|
||||
# The bread ecosystem (bakery + bread, breadbar, breadbox, breadcrumbs, breadpad)
|
||||
# is bakery-managed, not pacman: the binaries and bakery manifest live in
|
||||
# /etc/skel/.local (baked in at ISO build time) and are copied into the user's
|
||||
# home below, so the install works fully offline with no DNS for bakery/GitHub.
|
||||
# bos-settings is the only pacman bread package and was installed by unpackfs.
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Deploy dotfiles into the user's home (don't clobber existing files).
|
||||
# Deploy dotfiles + the bakery bread ecosystem into the user's home (Calamares
|
||||
# already seeds from /etc/skel, but copy explicitly too so a fresh install is
|
||||
# self-contained even if the users module skips skel). Don't clobber existing.
|
||||
# ---------------------------------------------------------------------------
|
||||
if [[ -n "$MAIN_USER" && -d /etc/skel/.config ]]; then
|
||||
mkdir -p "/home/$MAIN_USER/.config"
|
||||
cp -rn /etc/skel/.config/. "/home/$MAIN_USER/.config/" || true
|
||||
chown -R "$MAIN_USER:$MAIN_USER" "/home/$MAIN_USER/.config" || true
|
||||
if [[ -n "$MAIN_USER" && -d /etc/skel ]]; then
|
||||
for d in .config .local .cache; do
|
||||
[[ -d "/etc/skel/$d" ]] || continue
|
||||
mkdir -p "/home/$MAIN_USER/$d"
|
||||
cp -rn "/etc/skel/$d/." "/home/$MAIN_USER/$d/" || true
|
||||
chown -R "$MAIN_USER:$MAIN_USER" "/home/$MAIN_USER/$d" || true
|
||||
done
|
||||
sudo -u "$MAIN_USER" xdg-user-dirs-update || true
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -29,8 +29,21 @@ sequence:
|
|||
- networkcfg
|
||||
- hwclock
|
||||
- packages
|
||||
# archiso strips the kernel from the squashfs; stage it, drop the archiso
|
||||
# initramfs config, and write a stock mkinitcpio preset before initcpio runs.
|
||||
- shellprocess@kernel
|
||||
- bootloader
|
||||
# plymouthcfg sets the boot-splash theme and flags plymouth in use, so
|
||||
# initcpiocfg adds the plymouth hook to the initramfs that initcpio builds.
|
||||
- plymouthcfg
|
||||
# Native initramfs generation (works reliably here). The native `bootloader`
|
||||
# and `grubcfg` modules do NOT — in this archiso layout they leave the ESP
|
||||
# empty and abort the install, so GRUB is installed explicitly in
|
||||
# post-install.sh instead (grub-install --removable + NVRAM + grub-mkconfig,
|
||||
# the sequence verified to produce a bootable system).
|
||||
- initcpiocfg
|
||||
- initcpio
|
||||
# BOS finalization: GRUB install + cleanup + snapper + services + dotfiles.
|
||||
# All fast, and runs after initcpio so /boot has the kernel + initramfs.
|
||||
- shellprocess
|
||||
- umount
|
||||
- show:
|
||||
|
|
|
|||
12
iso/airootfs/etc/greetd/config.toml
Normal file
12
iso/airootfs/etc/greetd/config.toml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# greetd drives login on the INSTALLED system. It is shipped DISABLED in the
|
||||
# squashfs and enabled by post-install.sh; the live ISO instead autologins
|
||||
# liveuser on tty1 (see getty@tty1 drop-in) so the installer comes straight up.
|
||||
#
|
||||
# tuigreet shows a minimal greeter, then launches the BOS Hyprland session via
|
||||
# bos-session (which fixes up PATH for the bakery bread apps).
|
||||
[terminal]
|
||||
vt = 1
|
||||
|
||||
[default_session]
|
||||
command = "tuigreet --remember --time --cmd /usr/local/bin/bos-session"
|
||||
user = "greeter"
|
||||
44
iso/airootfs/etc/pacman.conf
Normal file
44
iso/airootfs/etc/pacman.conf
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#
|
||||
# BOS pacman.conf — used during ISO build and installed to the target system.
|
||||
# Based on the standard Arch Linux pacman.conf.
|
||||
#
|
||||
|
||||
[options]
|
||||
HoldPkg = pacman glibc
|
||||
Architecture = auto
|
||||
CheckSpace
|
||||
ParallelDownloads = 5
|
||||
|
||||
Color
|
||||
VerbosePkgLists
|
||||
ILoveCandy
|
||||
|
||||
SigLevel = Required DatabaseOptional
|
||||
LocalFileSigLevel = Optional
|
||||
|
||||
[core]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
[extra]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
[multilib]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Breadway custom repo — provides: bakery and the bread ecosystem packages
|
||||
# (bread, breadbar, breadbox, breadcrumbs, breadpad, bos-settings).
|
||||
# (calamares comes from the official extra repo, not here.)
|
||||
#
|
||||
# Packages are published to the Forgejo Arch registry (group "os") by the
|
||||
# .forgejo/workflows/package.yml workflow in each repo, on tag push.
|
||||
#
|
||||
# Forgejo signs the repo db with a key pacman can't look up, so TrustAll
|
||||
# fails. SigLevel = Never skips verification (acceptable for this private
|
||||
# repo over TLS). TODO: import Forgejo's signing key + SigLevel = Required.
|
||||
# -----------------------------------------------------------------------
|
||||
# The section name must match Forgejo's served db filename
|
||||
# ({owner}.{group}.{domain}.db) — pacman fetches "<section>.db" from Server.
|
||||
[Breadway.os.git.breadway.dev]
|
||||
SigLevel = Never
|
||||
Server = https://git.breadway.dev/api/packages/Breadway/arch/os/$arch
|
||||
11
iso/airootfs/etc/pacman.d/mirrorlist
Normal file
11
iso/airootfs/etc/pacman.d/mirrorlist
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# BOS default mirrorlist.
|
||||
#
|
||||
# geo.mirror.pkgbuild.com is the official Arch geo-IP redirect — it routes to a
|
||||
# nearby mirror anywhere in the world, so pacman works out of the box without
|
||||
# region-specific configuration. The others are reliable global fallbacks.
|
||||
#
|
||||
# To optimise for your location/speed later: sudo reflector --save \
|
||||
# /etc/pacman.d/mirrorlist --protocol https --latest 20 --sort rate
|
||||
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
|
||||
Server = https://mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
Server = https://mirror.leaseweb.net/archlinux/$repo/os/$arch
|
||||
9
iso/airootfs/etc/profile.d/bos-local-bin.sh
Normal file
9
iso/airootfs/etc/profile.d/bos-local-bin.sh
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Put the per-user bakery bin dir on PATH. The bread ecosystem (breadd, breadbar,
|
||||
# breadbox, …) is installed there by bakery, and the Hyprland session launches
|
||||
# them via `exec-once`, which resolves against the PATH it inherits from the
|
||||
# login shell. Arch's stock /etc/profile does not add ~/.local/bin, so do it here
|
||||
# for every login shell (live user and installed user alike).
|
||||
case ":$PATH:" in
|
||||
*":$HOME/.local/bin:"*) ;;
|
||||
*) export PATH="$HOME/.local/bin:$PATH" ;;
|
||||
esac
|
||||
28
iso/airootfs/etc/skel/.cache/wal/colors.json
Normal file
28
iso/airootfs/etc/skel/.cache/wal/colors.json
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"wallpaper": "/usr/share/backgrounds/bos/bread-background.png",
|
||||
"alpha": "100",
|
||||
|
||||
"special": {
|
||||
"background": "#0c0c0c",
|
||||
"foreground": "#e8e8e8",
|
||||
"cursor": "#eab672"
|
||||
},
|
||||
"colors": {
|
||||
"color0": "#1a1a1a",
|
||||
"color1": "#b98749",
|
||||
"color2": "#cd9450",
|
||||
"color3": "#e3a85c",
|
||||
"color4": "#eab672",
|
||||
"color5": "#f6c477",
|
||||
"color6": "#eabe82",
|
||||
"color7": "#d8d8d8",
|
||||
"color8": "#3a3a3a",
|
||||
"color9": "#b98749",
|
||||
"color10": "#cd9450",
|
||||
"color11": "#e3a85c",
|
||||
"color12": "#eab672",
|
||||
"color13": "#f6c477",
|
||||
"color14": "#eabe82",
|
||||
"color15": "#f5f5f5"
|
||||
}
|
||||
}
|
||||
3
iso/airootfs/etc/skel/.config/gtk-3.0/settings.ini
Normal file
3
iso/airootfs/etc/skel/.config/gtk-3.0/settings.ini
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[Settings]
|
||||
gtk-application-prefer-dark-theme=1
|
||||
gtk-theme-name=Adwaita-dark
|
||||
3
iso/airootfs/etc/skel/.config/gtk-4.0/settings.ini
Normal file
3
iso/airootfs/etc/skel/.config/gtk-4.0/settings.ini
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[Settings]
|
||||
gtk-application-prefer-dark-theme=1
|
||||
gtk-theme-name=Adwaita-dark
|
||||
37
iso/airootfs/etc/skel/.config/hypr/hypridle.conf
Normal file
37
iso/airootfs/etc/skel/.config/hypr/hypridle.conf
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# Idle management (hypridle). Conservative, mainstream-OS-like defaults:
|
||||
# dim -> screen off -> lock -> suspend, all respecting idle inhibitors (so media
|
||||
# playback, etc. won't dim or suspend the machine). Vendor-neutral: nothing here
|
||||
# is Intel/AMD specific.
|
||||
general {
|
||||
lock_cmd = pidof hyprlock || hyprlock
|
||||
before_sleep_cmd = loginctl lock-session
|
||||
after_sleep_cmd = hyprctl dispatch dpms on
|
||||
ignore_dbus_inhibit = false
|
||||
}
|
||||
|
||||
# Dim the backlight after 5 minutes (restored on activity). No-op on hardware
|
||||
# without a backlight (desktops / VMs).
|
||||
listener {
|
||||
timeout = 300
|
||||
on-timeout = brightnessctl -s set 10%
|
||||
on-resume = brightnessctl -r
|
||||
}
|
||||
|
||||
# Turn the display off after 8 minutes.
|
||||
listener {
|
||||
timeout = 480
|
||||
on-timeout = hyprctl dispatch dpms off
|
||||
on-resume = hyprctl dispatch dpms on
|
||||
}
|
||||
|
||||
# Lock shortly after the screen turns off.
|
||||
listener {
|
||||
timeout = 510
|
||||
on-timeout = loginctl lock-session
|
||||
}
|
||||
|
||||
# Suspend after 20 minutes of inactivity (skipped while something inhibits idle).
|
||||
listener {
|
||||
timeout = 1200
|
||||
on-timeout = systemctl suspend
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
monitor=,preferred,auto,1
|
||||
|
||||
exec-once = breadd
|
||||
exec-once = breadbar
|
||||
exec-once = breadbox-sync
|
||||
|
||||
source = ~/.config/hypr/keybinds.conf
|
||||
|
||||
general {
|
||||
gaps_in = 5
|
||||
gaps_out = 10
|
||||
border_size = 2
|
||||
col.active_border = rgba(88c0d0ff)
|
||||
col.inactive_border = rgba(4c566aff)
|
||||
layout = dwindle
|
||||
}
|
||||
|
||||
decoration {
|
||||
rounding = 8
|
||||
blur {
|
||||
enabled = true
|
||||
size = 6
|
||||
passes = 2
|
||||
}
|
||||
shadow {
|
||||
enabled = true
|
||||
range = 12
|
||||
render_power = 3
|
||||
}
|
||||
}
|
||||
|
||||
animations {
|
||||
enabled = true
|
||||
bezier = ease, 0.25, 0.1, 0.25, 1.0
|
||||
animation = windows, 1, 4, ease
|
||||
animation = fade, 1, 4, ease
|
||||
animation = workspaces, 1, 5, ease
|
||||
}
|
||||
|
||||
input {
|
||||
kb_layout = us
|
||||
follow_mouse = 1
|
||||
touchpad {
|
||||
natural_scroll = true
|
||||
}
|
||||
}
|
||||
|
||||
dwindle {
|
||||
preserve_split = true
|
||||
}
|
||||
|
||||
misc {
|
||||
disable_hyprland_logo = true
|
||||
disable_splash_rendering = true
|
||||
}
|
||||
168
iso/airootfs/etc/skel/.config/hypr/hyprland.lua
Normal file
168
iso/airootfs/etc/skel/.config/hypr/hyprland.lua
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
-- BOS Hyprland configuration — native Lua config (Hyprland 0.55+).
|
||||
-- hyprlang (.conf) is deprecated; this uses the built-in `hl` API.
|
||||
-- Single-file and non-modular by design. Reference: https://wiki.hypr.land/
|
||||
|
||||
local mod = "SUPER"
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Monitors — generic default that works on any hardware.
|
||||
-- ---------------------------------------------------------------------------
|
||||
hl.monitor({ output = "", mode = "preferred", position = "auto", scale = "auto" })
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Core settings.
|
||||
-- ---------------------------------------------------------------------------
|
||||
hl.config({
|
||||
general = {
|
||||
gaps_in = 5,
|
||||
gaps_out = 10,
|
||||
border_size = 2,
|
||||
col = {
|
||||
active_border = "rgba(88c0d0ff)",
|
||||
inactive_border = "rgba(4c566aff)",
|
||||
},
|
||||
layout = "dwindle",
|
||||
resize_on_border = true,
|
||||
},
|
||||
decoration = {
|
||||
rounding = 8,
|
||||
active_opacity = 1.0,
|
||||
inactive_opacity = 1.0,
|
||||
blur = {
|
||||
enabled = true,
|
||||
size = 6,
|
||||
passes = 2,
|
||||
new_optimizations = true,
|
||||
},
|
||||
shadow = {
|
||||
enabled = true,
|
||||
range = 12,
|
||||
render_power = 3,
|
||||
},
|
||||
},
|
||||
input = {
|
||||
kb_layout = "us",
|
||||
follow_mouse = 1,
|
||||
touchpad = { natural_scroll = true },
|
||||
},
|
||||
dwindle = {
|
||||
preserve_split = true,
|
||||
},
|
||||
animations = {
|
||||
enabled = true,
|
||||
},
|
||||
misc = {
|
||||
disable_hyprland_logo = true,
|
||||
disable_splash_rendering = true,
|
||||
},
|
||||
})
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Environment (vendor-neutral; no GPU-specific vars so it works on Intel/AMD).
|
||||
-- ---------------------------------------------------------------------------
|
||||
hl.env("XCURSOR_SIZE", "24")
|
||||
hl.env("HYPRCURSOR_SIZE", "24")
|
||||
hl.env("MOZ_ENABLE_WAYLAND", "1")
|
||||
hl.env("QT_QPA_PLATFORM", "wayland;xcb")
|
||||
hl.env("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1")
|
||||
hl.env("SDL_VIDEODRIVER", "wayland")
|
||||
hl.env("ELECTRON_OZONE_PLATFORM_HINT", "auto")
|
||||
hl.env("_JAVA_AWT_WM_NONREPARENTING", "1")
|
||||
|
||||
-- kitty sets its own background_opacity (see kitty.conf), so the global blur
|
||||
-- above blurs behind the terminal while keeping text fully opaque.
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Standard BOS keybinds (SUPER = mod).
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Apps / window management
|
||||
hl.bind(mod .. " + RETURN", hl.dsp.exec_cmd("kitty"))
|
||||
hl.bind(mod .. " + BACKSPACE", hl.dsp.window.close())
|
||||
hl.bind(mod .. " + SPACE", hl.dsp.exec_cmd("breadbox"))
|
||||
hl.bind(mod .. " + E", hl.dsp.exec_cmd("nautilus"))
|
||||
hl.bind(mod .. " + B", hl.dsp.exec_cmd("zen-browser"))
|
||||
hl.bind(mod .. " + U", hl.dsp.exec_cmd("breadpad"))
|
||||
hl.bind(mod .. " + M", hl.dsp.exec_cmd("breadman"))
|
||||
hl.bind(mod .. " + L", hl.dsp.exec_cmd("loginctl lock-session"))
|
||||
hl.bind(mod .. " + F", hl.dsp.window.fullscreen({ action = "toggle" }))
|
||||
hl.bind(mod .. " + V", hl.dsp.window.float({ action = "toggle" }))
|
||||
hl.bind(mod .. " + T", hl.dsp.layout("togglesplit"))
|
||||
hl.bind(mod .. " + Tab", hl.dsp.focus({ urgent_or_last = true }))
|
||||
hl.bind(mod .. " + N", hl.dsp.exit())
|
||||
|
||||
-- Screenshots (grim + slurp + wl-clipboard)
|
||||
hl.bind(mod .. " + SHIFT + S", hl.dsp.exec_cmd([[bash -c 'mkdir -p ~/Pictures/Screenshots && grim -g "$(slurp)" ~/Pictures/Screenshots/$(date +%Y%m%d-%H%M%S).png']]))
|
||||
hl.bind(mod .. " + SHIFT + C", hl.dsp.exec_cmd([[bash -c 'grim -g "$(slurp)" - | wl-copy']]))
|
||||
hl.bind(mod .. " + SHIFT + P", hl.dsp.exec_cmd([[bash -c 'mkdir -p ~/Pictures/Screenshots && grim ~/Pictures/Screenshots/$(date +%Y%m%d-%H%M%S).png']]))
|
||||
|
||||
-- Focus (directional)
|
||||
hl.bind(mod .. " + left", hl.dsp.focus({ direction = "left" }))
|
||||
hl.bind(mod .. " + right", hl.dsp.focus({ direction = "right" }))
|
||||
hl.bind(mod .. " + up", hl.dsp.focus({ direction = "up" }))
|
||||
hl.bind(mod .. " + down", hl.dsp.focus({ direction = "down" }))
|
||||
|
||||
-- Move window (directional, vim keys)
|
||||
hl.bind(mod .. " + SHIFT + h", hl.dsp.window.move({ direction = "left" }))
|
||||
hl.bind(mod .. " + SHIFT + j", hl.dsp.window.move({ direction = "down" }))
|
||||
hl.bind(mod .. " + SHIFT + k", hl.dsp.window.move({ direction = "up" }))
|
||||
hl.bind(mod .. " + SHIFT + l", hl.dsp.window.move({ direction = "right" }))
|
||||
|
||||
-- Resize active window (arrows)
|
||||
hl.bind(mod .. " + SHIFT + right", hl.dsp.window.resize({ x = 30, y = 0, relative = true }), { repeating = true })
|
||||
hl.bind(mod .. " + SHIFT + left", hl.dsp.window.resize({ x = -30, y = 0, relative = true }), { repeating = true })
|
||||
hl.bind(mod .. " + SHIFT + up", hl.dsp.window.resize({ x = 0, y = -30, relative = true }), { repeating = true })
|
||||
hl.bind(mod .. " + SHIFT + down", hl.dsp.window.resize({ x = 0, y = 30, relative = true }), { repeating = true })
|
||||
|
||||
-- Workspaces 1–10 (0 = workspace 10)
|
||||
for i = 1, 10 do
|
||||
local key = tostring(i % 10)
|
||||
hl.bind(mod .. " + " .. key, hl.dsp.focus({ workspace = i }))
|
||||
hl.bind(mod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = i }))
|
||||
end
|
||||
|
||||
-- Workspace cycling
|
||||
hl.bind(mod .. " + bracketright", hl.dsp.focus({ workspace = "e+1" }))
|
||||
hl.bind(mod .. " + bracketleft", hl.dsp.focus({ workspace = "e-1" }))
|
||||
hl.bind(mod .. " + SHIFT + bracketright", hl.dsp.window.move({ workspace = "e+1" }))
|
||||
hl.bind(mod .. " + SHIFT + bracketleft", hl.dsp.window.move({ workspace = "e-1" }))
|
||||
|
||||
-- Mouse
|
||||
hl.bind(mod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" }))
|
||||
hl.bind(mod .. " + mouse_up", hl.dsp.focus({ workspace = "e-1" }))
|
||||
hl.bind(mod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true })
|
||||
hl.bind(mod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })
|
||||
|
||||
-- Media / hardware keys (work locked, i.e. on the lock screen too)
|
||||
hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+"), { locked = true, repeating = true })
|
||||
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"), { locked = true, repeating = true })
|
||||
hl.bind("XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"), { locked = true })
|
||||
hl.bind("XF86AudioMicMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"), { locked = true })
|
||||
hl.bind("XF86MonBrightnessUp", hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%+"), { locked = true, repeating = true })
|
||||
hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%-"), { locked = true, repeating = true })
|
||||
hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"), { locked = true })
|
||||
hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { locked = true })
|
||||
hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Autostart. polkit agent + the bread ecosystem + idle daemon + wallpaper.
|
||||
-- (bos-live-setup appends the live-installer launch below this on the ISO.)
|
||||
-- ---------------------------------------------------------------------------
|
||||
hl.on("hyprland.start", function()
|
||||
local startup = {
|
||||
-- Prefer dark for GTK4/libadwaita apps (GTK3 uses settings.ini); without
|
||||
-- this nautilus/breadbox render in light mode.
|
||||
"gsettings set org.gnome.desktop.interface color-scheme prefer-dark",
|
||||
"gsettings set org.gnome.desktop.interface gtk-theme Adwaita-dark",
|
||||
"/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1",
|
||||
"awww-daemon",
|
||||
-- set the default wallpaper once the daemon is up (retry until ready)
|
||||
[[bash -c 'until awww img /usr/share/backgrounds/bos/bread-background.png 2>/dev/null; do sleep 0.3; done']],
|
||||
"breadd",
|
||||
"breadbar",
|
||||
"breadbox-sync",
|
||||
"hypridle",
|
||||
}
|
||||
for _, cmd in ipairs(startup) do
|
||||
hl.dispatch(hl.dsp.exec_cmd(cmd))
|
||||
end
|
||||
end)
|
||||
28
iso/airootfs/etc/skel/.config/hypr/hyprlock.conf
Normal file
28
iso/airootfs/etc/skel/.config/hypr/hyprlock.conf
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Lock screen (hyprlock). Solid dark background (no runtime-generated wallpaper
|
||||
# dependency), accent matched to the Hyprland border colour.
|
||||
general {
|
||||
hide_cursor = true
|
||||
}
|
||||
|
||||
background {
|
||||
monitor =
|
||||
color = rgba(46, 52, 64, 1.0)
|
||||
blur_passes = 0
|
||||
}
|
||||
|
||||
input-field {
|
||||
monitor =
|
||||
size = 20%, 5%
|
||||
outline_thickness = 3
|
||||
inner_color = rgba(0, 0, 0, 0.2)
|
||||
outer_color = rgba(136, 192, 208, 0.8)
|
||||
check_color = rgba(120, 220, 140, 0.95)
|
||||
fail_color = rgba(255, 90, 90, 0.95)
|
||||
font_color = rgba(255, 255, 255, 0.95)
|
||||
fade_on_empty = false
|
||||
rounding = 12
|
||||
placeholder_text = <i>Password…</i>
|
||||
position = 0, -20
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
$mod = SUPER
|
||||
|
||||
# App launchers
|
||||
bind = $mod, Space, exec, breadbox
|
||||
bind = $mod, N, exec, breadpad
|
||||
bind = $mod, M, exec, breadman
|
||||
bind = $mod, S, exec, bos-settings
|
||||
|
||||
# Core
|
||||
bind = $mod, Return, exec, foot
|
||||
bind = $mod, Q, killactive
|
||||
bind = $mod SHIFT, E, exit
|
||||
bind = $mod, F, fullscreen
|
||||
|
||||
# Focus
|
||||
bind = $mod, H, movefocus, l
|
||||
bind = $mod, L, movefocus, r
|
||||
bind = $mod, K, movefocus, u
|
||||
bind = $mod, J, movefocus, d
|
||||
|
||||
# Move windows
|
||||
bind = $mod SHIFT, H, movewindow, l
|
||||
bind = $mod SHIFT, L, movewindow, r
|
||||
bind = $mod SHIFT, K, movewindow, u
|
||||
bind = $mod SHIFT, J, movewindow, d
|
||||
|
||||
# Workspaces
|
||||
bind = $mod, 1, workspace, 1
|
||||
bind = $mod, 2, workspace, 2
|
||||
bind = $mod, 3, workspace, 3
|
||||
bind = $mod, 4, workspace, 4
|
||||
bind = $mod, 5, workspace, 5
|
||||
|
||||
bind = $mod SHIFT, 1, movetoworkspace, 1
|
||||
bind = $mod SHIFT, 2, movetoworkspace, 2
|
||||
bind = $mod SHIFT, 3, movetoworkspace, 3
|
||||
bind = $mod SHIFT, 4, movetoworkspace, 4
|
||||
bind = $mod SHIFT, 5, movetoworkspace, 5
|
||||
|
||||
# Scroll through workspaces
|
||||
bind = $mod, mouse_down, workspace, e+1
|
||||
bind = $mod, mouse_up, workspace, e-1
|
||||
|
||||
# Mouse binds
|
||||
bindm = $mod, mouse:272, movewindow
|
||||
bindm = $mod, mouse:273, resizewindow
|
||||
|
||||
# Volume
|
||||
bind = , XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
|
||||
bind = , XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
|
||||
bind = , XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
|
||||
|
||||
# Brightness
|
||||
bind = , XF86MonBrightnessUp, exec, brightnessctl set 5%+
|
||||
bind = , XF86MonBrightnessDown, exec, brightnessctl set 5%-
|
||||
|
||||
# Screenshot
|
||||
bind = , Print, exec, grimblast copy area
|
||||
13
iso/airootfs/etc/skel/.config/kitty/kitty.conf
Normal file
13
iso/airootfs/etc/skel/.config/kitty/kitty.conf
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# BOS kitty config.
|
||||
# Translucent background so Hyprland's blur shows through behind the terminal,
|
||||
# while text stays fully opaque. Colours are left to kitty's default / pywal.
|
||||
background_opacity 0.88
|
||||
background_blur 1
|
||||
|
||||
font_family JetBrains Mono
|
||||
font_size 11.0
|
||||
cursor_shape beam
|
||||
scrollback_lines 10000
|
||||
enable_audio_bell no
|
||||
window_padding_width 8
|
||||
confirm_os_window_close 0
|
||||
7
iso/airootfs/etc/systemd/logind.conf.d/90-bos-power.conf
Normal file
7
iso/airootfs/etc/systemd/logind.conf.d/90-bos-power.conf
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Lid behaviour: suspend on close (on battery or AC), but ignore the lid when
|
||||
# docked / an external display is connected so closing the laptop with a monitor
|
||||
# attached keeps the session running. Mainstream-desktop default.
|
||||
[Login]
|
||||
HandleLidSwitch=suspend
|
||||
HandleLidSwitchExternalPower=suspend
|
||||
HandleLidSwitchDocked=ignore
|
||||
|
|
@ -0,0 +1 @@
|
|||
/usr/lib/systemd/system/NetworkManager.service
|
||||
|
|
@ -3,8 +3,9 @@
|
|||
#
|
||||
# archiso keeps vmlinuz/initramfs in the ISO boot dir (arch/boot/x86_64/), NOT
|
||||
# in the squashfs, so the rootfs that unpackfs lays down has an empty /boot.
|
||||
# Without a kernel, the chroot's `mkinitcpio -P` and `grub-mkconfig` produce
|
||||
# nothing and the installed system is unbootable.
|
||||
# The kernel must be present before Calamares' `initcpio` module runs mkinitcpio
|
||||
# (the stock linux.preset points ALL_kver at /boot/vmlinuz-linux) and before the
|
||||
# `bootloader` module runs grub — otherwise the installed system is unbootable.
|
||||
#
|
||||
# Runs in the LIVE environment (Calamares shellprocess, dontChroot) so it can
|
||||
# read /run/archiso/bootmnt; the target root mount point is passed as $1.
|
||||
|
|
@ -21,4 +22,25 @@ for u in amd-ucode.img intel-ucode.img; do
|
|||
[ -f "$SRC/$u" ] && cp -f "$SRC/$u" "$ROOT/boot/$u"
|
||||
done
|
||||
|
||||
echo "Copied live kernel into $ROOT/boot"
|
||||
# Replace the archiso initramfs setup that unpackfs copied from the live medium.
|
||||
# On archiso the linux preset is PRESETS=('archiso') using archiso.conf (the live
|
||||
# HOOKS). Calamares' `initcpio` runs `mkinitcpio -P`, which would build that
|
||||
# archiso preset and either bake the live-boot hooks into the install or fail
|
||||
# once archiso.conf is gone. Drop the drop-in and write a stock default+fallback
|
||||
# preset so `initcpio` produces a normal, bootable initramfs from the config that
|
||||
# the `initcpiocfg` module generates at /etc/mkinitcpio.conf.
|
||||
rm -f "$ROOT/etc/mkinitcpio.conf.d/archiso.conf"
|
||||
install -d -m 0755 "$ROOT/etc/mkinitcpio.d"
|
||||
cat >"$ROOT/etc/mkinitcpio.d/linux.preset" <<'PRESET'
|
||||
# mkinitcpio preset file for the 'linux' package
|
||||
ALL_config="/etc/mkinitcpio.conf"
|
||||
ALL_kver="/boot/vmlinuz-linux"
|
||||
|
||||
PRESETS=('default' 'fallback')
|
||||
|
||||
default_image="/boot/initramfs-linux.img"
|
||||
fallback_image="/boot/initramfs-linux-fallback.img"
|
||||
fallback_options="-S autodetect"
|
||||
PRESET
|
||||
|
||||
echo "Copied live kernel into $ROOT/boot; reset mkinitcpio to a stock preset"
|
||||
|
|
|
|||
|
|
@ -19,16 +19,16 @@ if ! id liveuser &>/dev/null; then
|
|||
fi
|
||||
|
||||
# Layer the installer onto the live desktop: auto-launch it, and bind Super+I to
|
||||
# relaunch it after it's been closed. Appended to (not replacing) the skel
|
||||
# Hyprland config so the full desktop stays intact.
|
||||
HYPR=/home/liveuser/.config/hypr/hyprland.conf
|
||||
# relaunch it after it's been closed. Appended (in Lua) to the skel hyprland.lua
|
||||
# native config so the full desktop stays intact.
|
||||
HYPR=/home/liveuser/.config/hypr/hyprland.lua
|
||||
install -d -m 0755 -o liveuser -g liveuser /home/liveuser/.config/hypr
|
||||
if ! grep -q bos-launch-calamares "$HYPR" 2>/dev/null; then
|
||||
cat >>"$HYPR" <<'EOF'
|
||||
|
||||
# --- live-media installer (added by bos-live-setup; absent on installed system) ---
|
||||
exec-once = bos-launch-calamares
|
||||
bind = SUPER, I, exec, bos-launch-calamares
|
||||
-- --- live-media installer (added by bos-live-setup; absent on installed system) ---
|
||||
hl.bind("SUPER + I", hl.dsp.exec_cmd("bos-launch-calamares"))
|
||||
hl.on("hyprland.start", function() hl.dispatch(hl.dsp.exec_cmd("bos-launch-calamares")) end)
|
||||
EOF
|
||||
fi
|
||||
|
||||
|
|
|
|||
15
iso/airootfs/usr/local/bin/bos-session
Normal file
15
iso/airootfs/usr/local/bin/bos-session
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/bash
|
||||
# BOS graphical session launcher, run by greetd on the INSTALLED system after
|
||||
# the user authenticates (see /etc/greetd/config.toml).
|
||||
#
|
||||
# greetd does not start a login shell, so /etc/profile.d is never sourced — which
|
||||
# means ~/.local/bin (where bakery installs the bread ecosystem: breadd, breadbar,
|
||||
# breadbox-sync, …) would be missing from PATH and the Hyprland `exec-once`
|
||||
# launches would fail. Source the login profile here so PATH is correct, set the
|
||||
# Wayland session hints, then hand off to Hyprland.
|
||||
source /etc/profile 2>/dev/null
|
||||
|
||||
export XDG_SESSION_TYPE=wayland
|
||||
export XDG_CURRENT_DESKTOP=Hyprland
|
||||
|
||||
exec Hyprland
|
||||
BIN
iso/airootfs/usr/share/backgrounds/bos/bread-background.png
Normal file
BIN
iso/airootfs/usr/share/backgrounds/bos/bread-background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 MiB |
BIN
iso/airootfs/usr/share/fonts/TTF/VarelaRound-Regular.ttf
Normal file
BIN
iso/airootfs/usr/share/fonts/TTF/VarelaRound-Regular.ttf
Normal file
Binary file not shown.
8
iso/airootfs/usr/share/plymouth/themes/bos/bos.plymouth
Normal file
8
iso/airootfs/usr/share/plymouth/themes/bos/bos.plymouth
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[Plymouth Theme]
|
||||
Name=BOS
|
||||
Description=Bread Operating System boot splash — logo, spinner, status
|
||||
ModuleName=script
|
||||
|
||||
[script]
|
||||
ImageDir=/usr/share/plymouth/themes/bos
|
||||
ScriptFile=/usr/share/plymouth/themes/bos/bos.script
|
||||
49
iso/airootfs/usr/share/plymouth/themes/bos/bos.script
Normal file
49
iso/airootfs/usr/share/plymouth/themes/bos/bos.script
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# BOS Plymouth boot splash (script module).
|
||||
# Bread-brown background, centred white BOS logo, a spinning accent ring, and a
|
||||
# status line at the bottom. Colours match the bread palette.
|
||||
|
||||
# --- background (#230b00) ---
|
||||
Window.SetBackgroundTopColor(0.137, 0.043, 0.0);
|
||||
Window.SetBackgroundBottomColor(0.137, 0.043, 0.0);
|
||||
|
||||
screen_w = Window.GetWidth();
|
||||
screen_h = Window.GetHeight();
|
||||
|
||||
# --- logo (centred, slightly above the middle) ---
|
||||
logo.image = Image("logo.png");
|
||||
logo.sprite = Sprite(logo.image);
|
||||
logo.x = screen_w / 2 - logo.image.GetWidth() / 2;
|
||||
logo.y = screen_h / 2 - logo.image.GetHeight() / 2 - 40;
|
||||
logo.sprite.SetX(logo.x);
|
||||
logo.sprite.SetY(logo.y);
|
||||
logo.sprite.SetZ(1);
|
||||
|
||||
# --- spinner (rotating accent ring, below the logo) ---
|
||||
spinner.image = Image("spinner.png");
|
||||
spinner.sprite = Sprite();
|
||||
spinner.cx = screen_w / 2;
|
||||
spinner.cy = logo.y + logo.image.GetHeight() + 60;
|
||||
spinner.angle = 0;
|
||||
|
||||
fun refresh_callback() {
|
||||
spinner.angle += 0.10;
|
||||
if (spinner.angle > 6.28318) spinner.angle -= 6.28318;
|
||||
rotated = spinner.image.Rotate(spinner.angle);
|
||||
spinner.sprite.SetImage(rotated);
|
||||
spinner.sprite.SetX(spinner.cx - rotated.GetWidth() / 2);
|
||||
spinner.sprite.SetY(spinner.cy - rotated.GetHeight() / 2);
|
||||
spinner.sprite.SetZ(2);
|
||||
}
|
||||
Plymouth.SetRefreshFunction(refresh_callback);
|
||||
|
||||
# --- status line (cream text, near the bottom) ---
|
||||
status.sprite = Sprite();
|
||||
fun show_status(text) {
|
||||
status.image = Image.Text(text, 0.945, 0.863, 0.741);
|
||||
status.sprite.SetImage(status.image);
|
||||
status.sprite.SetX(screen_w / 2 - status.image.GetWidth() / 2);
|
||||
status.sprite.SetY(screen_h * 0.84);
|
||||
status.sprite.SetZ(2);
|
||||
}
|
||||
Plymouth.SetMessageFunction(show_status);
|
||||
Plymouth.SetUpdateStatusFunction(show_status);
|
||||
BIN
iso/airootfs/usr/share/plymouth/themes/bos/logo.png
Normal file
BIN
iso/airootfs/usr/share/plymouth/themes/bos/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
BIN
iso/airootfs/usr/share/plymouth/themes/bos/spinner.png
Normal file
BIN
iso/airootfs/usr/share/plymouth/themes/bos/spinner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1 KiB |
|
|
@ -4,6 +4,21 @@ base-devel
|
|||
linux
|
||||
linux-firmware
|
||||
linux-headers
|
||||
# CPU microcode — applied early by GRUB on the installed system (picked up by
|
||||
# the bootloader module). amd-ucode for the dev laptop's Ryzen; intel-ucode for
|
||||
# Intel targets. bos-copy-kernel also stages these into the live target /boot.
|
||||
amd-ucode
|
||||
intel-ucode
|
||||
|
||||
# Power management (vendor-neutral; works on Intel and AMD). tlp auto-tunes power
|
||||
# by AC/battery and CPU driver; hypridle/hyprlock handle idle dim/off/lock/suspend
|
||||
# and the lock screen; upower exposes battery state. NOT power-profiles-daemon —
|
||||
# it conflicts with tlp.
|
||||
tlp
|
||||
tlp-rdw
|
||||
upower
|
||||
hypridle
|
||||
hyprlock
|
||||
|
||||
# Bootloader + filesystem
|
||||
grub
|
||||
|
|
@ -37,6 +52,10 @@ inotify-tools
|
|||
# Wayland / Hyprland
|
||||
hyprland
|
||||
xdg-desktop-portal-hyprland
|
||||
# Login manager for the installed system (Wayland-native; enabled by
|
||||
# post-install.sh, launches the Hyprland session via tuigreet → bos-session).
|
||||
greetd
|
||||
greetd-tuigreet
|
||||
xdg-utils
|
||||
xdg-user-dirs
|
||||
polkit
|
||||
|
|
@ -53,7 +72,8 @@ pipewire-jack
|
|||
networkmanager
|
||||
network-manager-applet
|
||||
iw
|
||||
iwd
|
||||
# Wi-Fi backend for NetworkManager (its default; no extra config needed).
|
||||
wpa_supplicant
|
||||
bluez
|
||||
bluez-utils
|
||||
|
||||
|
|
@ -73,29 +93,47 @@ noto-fonts-emoji
|
|||
ttf-jetbrains-mono
|
||||
|
||||
# Terminal
|
||||
foot
|
||||
kitty
|
||||
|
||||
# File manager
|
||||
nautilus
|
||||
# Web browser (served from the [Breadway] repo; AUR zen-browser-bin republished
|
||||
# there so the ISO build can pull it via pacman). mailcap satisfies zen's
|
||||
# mime-types dependency explicitly.
|
||||
zen-browser-bin
|
||||
mailcap
|
||||
|
||||
# Installer — Calamares is AUR-only; built in-house and served from [breadway]
|
||||
# (calamares 3.4.x is already Qt6; there is no separate calamares-qt6 package)
|
||||
calamares
|
||||
|
||||
# Bread ecosystem — sourced from [breadway] repo. Baked into the squashfs so a
|
||||
# fresh install (and the live session) has the full desktop with no network.
|
||||
bakery
|
||||
bread
|
||||
breadbar
|
||||
breadbox
|
||||
breadcrumbs
|
||||
breadpad
|
||||
# Bread ecosystem.
|
||||
#
|
||||
# The bread apps themselves (bakery, bread, breadbar, breadbox, breadcrumbs,
|
||||
# breadpad) are NOT pacman packages here — they are bakery-managed binaries
|
||||
# baked into /etc/skel/.local/bin at build time (see build-local.sh), so every
|
||||
# user gets the exact versions from this laptop's bakery install with no
|
||||
# network/DNS needed at install or runtime. Their runtime system deps are pulled
|
||||
# in elsewhere in this list (gtk4, gtk4-layer-shell, iw, libpulse, librsvg,
|
||||
# networkmanager, openssl, zlib, systemd-libs) — keep those even though no bread
|
||||
# package depends on them.
|
||||
#
|
||||
# bos-settings is a BOS-specific pacman package (not part of the bakery index),
|
||||
# so it stays here, served from the [breadway] repo.
|
||||
bos-settings
|
||||
|
||||
# Input / screen utilities
|
||||
brightnessctl
|
||||
grim
|
||||
slurp
|
||||
# Clipboard (Wayland copy/paste; also clipboard screenshots) and media keys.
|
||||
wl-clipboard
|
||||
playerctl
|
||||
# Wallpaper daemon + pywal (drives the bread* colour palette from the wallpaper).
|
||||
awww
|
||||
python-pywal
|
||||
# Boot splash (BOS logo + spinner instead of kernel text).
|
||||
plymouth
|
||||
|
||||
# Utilities
|
||||
sudo
|
||||
|
|
@ -110,5 +148,32 @@ man-db
|
|||
man-pages
|
||||
less
|
||||
|
||||
# Base CLI tools every install should have.
|
||||
# Editors
|
||||
nano
|
||||
micro
|
||||
vim
|
||||
# Shell UX
|
||||
bash-completion
|
||||
# System / hardware inspection
|
||||
htop
|
||||
usbutils
|
||||
pciutils
|
||||
dmidecode
|
||||
lsof
|
||||
tree
|
||||
fastfetch
|
||||
# Removable-media filesystems (USB sticks, external drives)
|
||||
ntfs-3g
|
||||
exfatprogs
|
||||
# Archives
|
||||
7zip
|
||||
zip
|
||||
unrar
|
||||
# Remote access (ssh client; sshd ships disabled)
|
||||
openssh
|
||||
# Mirror management (refresh /etc/pacman.d/mirrorlist for the user's location)
|
||||
reflector
|
||||
|
||||
# Dev tools (for bos-settings standalone install)
|
||||
rustup
|
||||
|
|
|
|||
|
|
@ -20,4 +20,5 @@ file_permissions=(
|
|||
["/usr/local/bin/bos-live-setup"]="0:0:755"
|
||||
["/usr/local/bin/bos-launch-calamares"]="0:0:755"
|
||||
["/usr/local/bin/bos-copy-kernel"]="0:0:755"
|
||||
["/usr/local/bin/bos-session"]="0:0:755"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue