From ee401ff5b402680a5d942eb3ab8bcddabdfdf97f Mon Sep 17 00:00:00 2001 From: Nucleic Date: Tue, 21 Jul 2026 01:19:00 -0700 Subject: [PATCH] Merge nucleic/lucid-lunar-wren-wxyw into dev --- SNAPSHOT.forky | 1 + mkimage/build-rootfs.sh | 25 +++++++- mkimage/hooks/00-identity.sh | 17 +++++- mkimage/profiles/vm-desktop.late-pkgs | 11 ++++ mkimage/profiles/vm-desktop.naros-pkgs | 12 ++++ mkimage/profiles/vm-desktop.pkgs | 58 +++++++++++++++++++ packages/naros-desktop-config/control | 14 +++++ .../files/etc/dconf/db/local.d/00-nucleic | 32 ++++++++++ .../files/etc/dconf/profile/user | 2 + .../files/etc/environment.d/90-nucleic.conf | 4 ++ .../files/etc/sudoers.d/naros-agent | 3 + packages/naros-desktop-config/postinst | 42 ++++++++++++++ packages/naros-desktop-config/stage.sh | 11 ++++ packages/naros-tier-vm-desktop/control | 15 +++++ packages/nucleic-a11y-agent/control | 13 +++++ packages/nucleic-a11y-agent/stage.sh | 21 +++++++ 16 files changed, 275 insertions(+), 6 deletions(-) create mode 100644 SNAPSHOT.forky create mode 100644 mkimage/profiles/vm-desktop.late-pkgs create mode 100644 mkimage/profiles/vm-desktop.naros-pkgs create mode 100644 mkimage/profiles/vm-desktop.pkgs create mode 100644 packages/naros-desktop-config/control create mode 100644 packages/naros-desktop-config/files/etc/dconf/db/local.d/00-nucleic create mode 100644 packages/naros-desktop-config/files/etc/dconf/profile/user create mode 100644 packages/naros-desktop-config/files/etc/environment.d/90-nucleic.conf create mode 100644 packages/naros-desktop-config/files/etc/sudoers.d/naros-agent create mode 100644 packages/naros-desktop-config/postinst create mode 100644 packages/naros-desktop-config/stage.sh create mode 100644 packages/naros-tier-vm-desktop/control create mode 100644 packages/nucleic-a11y-agent/control create mode 100644 packages/nucleic-a11y-agent/stage.sh diff --git a/SNAPSHOT.forky b/SNAPSHOT.forky new file mode 100644 index 0000000..45781a3 --- /dev/null +++ b/SNAPSHOT.forky @@ -0,0 +1 @@ +20260701T000000Z diff --git a/mkimage/build-rootfs.sh b/mkimage/build-rootfs.sh index 2747375..76a1d88 100755 --- a/mkimage/build-rootfs.sh +++ b/mkimage/build-rootfs.sh @@ -25,8 +25,26 @@ while [ $# -gt 0 ]; do done VERSION="$(cat "$OS_DIR/VERSION")" -SNAPSHOT="$(cat "$OS_DIR/SNAPSHOT")" -SUITE="trixie" +# Per-flavor base (NAROS.md §7.4): the VM DESKTOP flavor (N5) builds entirely from a pinned +# Debian FORKY (testing) snapshot for GNOME 50 — trixie ships only GNOME 48 — while every +# other tier, including the HEADLESS VM, stays on the trixie snapshot. One coherent pocket per +# rootfs, no trixie/forky ABI mixing. VARIANT is the os-release identity class +# (base/agent/runner/vm, §2.3); FLAVOR distinguishes the two VM rootfs builds within +# VARIANT=vm (headless vs desktop). +case "$TIER" in + vm-desktop) + SUITE="forky"; VARIANT="vm"; FLAVOR="desktop" + SNAPSHOT="$(cat "$OS_DIR/SNAPSHOT.forky" 2>/dev/null || cat "$OS_DIR/SNAPSHOT")" + ;; + vm) + SUITE="trixie"; VARIANT="vm"; FLAVOR="headless" + SNAPSHOT="$(cat "$OS_DIR/SNAPSHOT")" + ;; + *) + SUITE="trixie"; VARIANT="$TIER"; FLAVOR="" + SNAPSHOT="$(cat "$OS_DIR/SNAPSHOT")" + ;; +esac MIRROR="https://snapshot.debian.org/archive/debian/${SNAPSHOT}/" PROFILE="$OS_DIR/mkimage/profiles/$TIER.pkgs" [ -f "$PROFILE" ] || { echo "no profile for tier '$TIER' ($PROFILE)" >&2; exit 2; } @@ -89,7 +107,8 @@ mkdir -p "$OUT" TAR="$OUT/naros-$TIER-$VERSION-$ARCH.tar" export NAROS_TIER="$TIER" NAROS_VERSION="$VERSION" NAROS_ARCH="$ARCH" \ - NAROS_CHANNEL="$CHANNEL" NAROS_SNAPSHOT="$SNAPSHOT" NAROS_SUITE="$SUITE" + NAROS_CHANNEL="$CHANNEL" NAROS_SNAPSHOT="$SNAPSHOT" NAROS_SUITE="$SUITE" \ + NAROS_VARIANT="$VARIANT" NAROS_FLAVOR="$FLAVOR" HOOKS=() if [ "${#LATE_DEBS[@]}" -gt 0 ]; then diff --git a/mkimage/hooks/00-identity.sh b/mkimage/hooks/00-identity.sh index 138207d..590be6e 100755 --- a/mkimage/hooks/00-identity.sh +++ b/mkimage/hooks/00-identity.sh @@ -6,6 +6,15 @@ set -eu R="$1" +# VARIANT is the os-release identity class (base/agent/runner/vm, §2.3); the build passes it +# separately from NAROS_TIER so the two VM flavors (vm, vm-desktop) both report VARIANT=vm and +# carry the headless/desktop distinction in NAROS_FLAVOR. Fallback to the tier for older callers. +VARIANT="${NAROS_VARIANT:-$NAROS_TIER}" +FLAVOR="${NAROS_FLAVOR:-}" +# naros-init/systemd role: the VM tiers boot as a guest (systemd PID 1, §5); everything else is +# a container surface. +case "$VARIANT" in vm) ROLE="vm" ;; *) ROLE="container" ;; esac + # mmdebstrap writes every build source into the target's sources.list — including the # CI-local [trusted=yes] copy:// pool, which doesn't exist at runtime and would fail # every `apt update` in a running container. Keep only the real mirrors (the pinned @@ -21,8 +30,8 @@ ID_LIKE=debian VERSION_ID="$NAROS_VERSION" VERSION="$NAROS_VERSION ($NAROS_CHANNEL)" VERSION_CODENAME=$NAROS_SUITE -VARIANT="$NAROS_TIER" -VARIANT_ID=$NAROS_TIER +VARIANT="$VARIANT" +VARIANT_ID=$VARIANT HOME_URL="https://github.com/abkslm/nucleic" DOCUMENTATION_URL="https://github.com/abkslm/nucleic/blob/main/docs/NAROS.md" EOF @@ -30,7 +39,7 @@ EOF mkdir -p "$R/etc/naros" echo "$NAROS_CHANNEL" > "$R/etc/naros/channel" echo "$NAROS_SNAPSHOT" > "$R/etc/naros/snapshot-date" -echo "container" > "$R/etc/naros/role" +echo "$ROLE" > "$R/etc/naros/role" # Capability manifest (NAROS.md §6.3). Base fields here; toolchain entries are appended # by the tiers that install them (agent-tier hook, N2). Versions of Nucleic packages are @@ -43,6 +52,8 @@ cat > "$R/etc/naros/manifest.json" < +Section: misc +Priority: optional +Depends: gdm3, dconf-cli, dbus, at-spi2-core, nash +Description: narOS VM desktop configuration (NAROS.md §7.4 N5; LINUX_VM_SEMANTIC_AGENT.md) + The Nucleic desktop policy the old Ubuntu provisioner applied by hand, packaged: + the `agent` auto-login account (uid 501, nash shell, passwordless sudo), GDM + Wayland auto-login, system dconf defaults (AT-SPI on, integer scale = 1, no + idle/lock/blank, GNOME welcome suppressed, the Mutter geometry-helper extension + enabled), the geometry-helper GNOME Shell extension itself, QT_ACCESSIBILITY, and + boot-to-graphical. Installing it turns the naros base into the computer-use guest. diff --git a/packages/naros-desktop-config/files/etc/dconf/db/local.d/00-nucleic b/packages/naros-desktop-config/files/etc/dconf/db/local.d/00-nucleic new file mode 100644 index 0000000..7113053 --- /dev/null +++ b/packages/naros-desktop-config/files/etc/dconf/db/local.d/00-nucleic @@ -0,0 +1,32 @@ +# System-wide dconf defaults for the naros-vm desktop guest (NAROS.md §7.4 N5). Applied to the +# auto-login agent session without a per-user seed. Ported from the old Ubuntu provisioner's +# dconf block (docs/LINUX_VM_SEMANTIC_AGENT.md Phase 2). `dconf update` (postinst) compiles this. +[org/gnome/desktop/interface] +# Turn the AT-SPI bridge on for GTK/GNOME apps so the semantic agent sees their trees — the +# whole point of the desktop flavor. +toolkit-accessibility=true +# Integer display scale = 1 (no fractional scaling): the invariant that makes the compositor's +# window coordinates equal the virtio-gpu scanout pixels the host captures 1:1, so ax_dump +# frames are directly clickable. +scaling-factor=uint32 1 + +[org/gnome/mutter] +# Do NOT enable fractional scaling — keep logical == physical pixels. +experimental-features=@as [] + +[org/gnome/desktop/session] +idle-delay=uint32 0 + +[org/gnome/desktop/screensaver] +lock-enabled=false +idle-activation-enabled=false + +[org/gnome/settings-daemon/plugins/power] +sleep-inactive-ac-type='nothing' +sleep-inactive-battery-type='nothing' + +[org/gnome/shell] +welcome-dialog-last-shown-version='99.0' +disable-user-extensions=false +# The Nucleic Mutter geometry helper (focused-window global origin for the AT-SPI agent). +enabled-extensions=['nucleic-geometry@nucleic.xyz'] diff --git a/packages/naros-desktop-config/files/etc/dconf/profile/user b/packages/naros-desktop-config/files/etc/dconf/profile/user new file mode 100644 index 0000000..aca0641 --- /dev/null +++ b/packages/naros-desktop-config/files/etc/dconf/profile/user @@ -0,0 +1,2 @@ +user-db:user +system-db:local diff --git a/packages/naros-desktop-config/files/etc/environment.d/90-nucleic.conf b/packages/naros-desktop-config/files/etc/environment.d/90-nucleic.conf new file mode 100644 index 0000000..81fd72b --- /dev/null +++ b/packages/naros-desktop-config/files/etc/environment.d/90-nucleic.conf @@ -0,0 +1,4 @@ +# Qt apps read this to enable their AT-SPI bridge (GTK does so automatically once the a11y bus +# is up). systemd's user session sources /etc/environment.d/*.conf into the graphical session. +# Chromium/Electron still need a per-launch --force-renderer-accessibility (the agent handles it). +QT_ACCESSIBILITY=1 diff --git a/packages/naros-desktop-config/files/etc/sudoers.d/naros-agent b/packages/naros-desktop-config/files/etc/sudoers.d/naros-agent new file mode 100644 index 0000000..cea6cea --- /dev/null +++ b/packages/naros-desktop-config/files/etc/sudoers.d/naros-agent @@ -0,0 +1,3 @@ +# narOS agent user (NAROS.md §6.1): frictionless escalation for `apt install` etc., +# non-interactive. The disposable, NAT-isolated VM is the isolation boundary. +agent ALL=(ALL) NOPASSWD:ALL diff --git a/packages/naros-desktop-config/postinst b/packages/naros-desktop-config/postinst new file mode 100644 index 0000000..a62cfe4 --- /dev/null +++ b/packages/naros-desktop-config/postinst @@ -0,0 +1,42 @@ +#!/bin/sh +# Realize the naros-vm desktop policy (NAROS.md §7.4 N5). Runs at image-build configure time in +# the mmdebstrap chroot (no running systemd) — every step is offline-safe. +set -e +[ "$1" = "configure" ] || exit 0 + +# 1. The narOS `agent` user GDM auto-logs into. uid 501 is in lockstep with the sandbox/agent +# tiers (the uid ContainerEngine execs as); login shell is the contract nash path. +if ! id -u agent >/dev/null 2>&1; then + useradd --uid 501 --user-group --create-home --home-dir /home/agent \ + --shell /usr/local/bin/nash agent +fi +for g in video input render sudo; do + getent group "$g" >/dev/null 2>&1 && usermod -aG "$g" agent || true +done +passwd -l agent >/dev/null 2>&1 || true # auto-login only, no password + +# 2. sudoers drop-in must be 0440 (git can't track that mode). +chmod 0440 /etc/sudoers.d/naros-agent 2>/dev/null || true + +# 3. GDM auto-login into the agent's Wayland session, so the host surface sees a live screen. +# (Debian gdm3 reads /etc/gdm3/daemon.conf; we own the desktop policy, so write it whole.) +mkdir -p /etc/gdm3 +cat > /etc/gdm3/daemon.conf <<'GDM' +[daemon] +WaylandEnable=true +AutomaticLoginEnable=true +AutomaticLogin=agent +GDM + +# 4. Compile the system dconf defaults (AT-SPI on, scale=1, no idle/lock, geometry ext enabled). +dconf update 2>/dev/null || true + +# 5. Boot to the graphical session. +systemctl set-default graphical.target >/dev/null 2>&1 || true + +# 6. Skip GNOME's first-run tour so the first host screenshot is a usable desktop. +mkdir -p /home/agent/.config +echo yes > /home/agent/.config/gnome-initial-setup-done +chown -R agent:agent /home/agent/.config 2>/dev/null || true + +exit 0 diff --git a/packages/naros-desktop-config/stage.sh b/packages/naros-desktop-config/stage.sh new file mode 100644 index 0000000..fd1a434 --- /dev/null +++ b/packages/naros-desktop-config/stage.sh @@ -0,0 +1,11 @@ +# Stage the Mutter geometry-helper GNOME Shell extension (guest/mutter-geometry-helper) into +# the system extensions dir. It exposes the focused window's true global origin over a private +# D-Bus name for the AT-SPI agent (AT-SPI loses the window origin on Wayland) — enabled via the +# dconf default in files/etc/dconf/db/local.d/00-nucleic. Arch-independent (JS + metadata). +stage() { + local dest="$1" + local ext="$dest/usr/share/gnome-shell/extensions/nucleic-geometry@nucleic.xyz" + local src="$OS_DIR/../guest/mutter-geometry-helper" + install -D -m 0644 "$src/metadata.json" "$ext/metadata.json" + install -D -m 0644 "$src/extension.js" "$ext/extension.js" +} diff --git a/packages/naros-tier-vm-desktop/control b/packages/naros-tier-vm-desktop/control new file mode 100644 index 0000000..f09b3a4 --- /dev/null +++ b/packages/naros-tier-vm-desktop/control @@ -0,0 +1,15 @@ +Package: naros-tier-vm-desktop +Version: @VERSION@ +Architecture: all +Maintainer: Nucleic +Section: metapackages +Priority: optional +Depends: naros-tier-vm, naros-desktop-config, nucleic-a11y-agent, gnome-session, gnome-shell, gdm3, at-spi2-core, xwayland, firefox-esr +Description: narOS VM guest tier — desktop flavor (GNOME 50, NAROS.md §7.4, milestone N5) + The full computer-use / semantic-agent surface, layered on the headless VM tier + (naros-tier-vm). Ties together the GNOME 50 / Mutter Wayland session (baked from + the pinned Debian forky snapshot), GDM auto-login, the AT-SPI accessibility bus, + the Rust semantic agent (nucleic-a11y-agent), and the Nucleic desktop config + (naros-desktop-config: agent auto-login user, dconf defaults, Mutter geometry + helper, Firefox policy). Built into the naros-vm-desktop rootfs, not apt-installed + at firstboot. diff --git a/packages/nucleic-a11y-agent/control b/packages/nucleic-a11y-agent/control new file mode 100644 index 0000000..24a7a5a --- /dev/null +++ b/packages/nucleic-a11y-agent/control @@ -0,0 +1,13 @@ +Package: nucleic-a11y-agent +Version: @VERSION@ +Architecture: @ARCH@ +Maintainer: Nucleic +Section: admin +Priority: optional +Depends: at-spi2-core +Description: Nucleic Linux guest AT-SPI semantic agent (NAROS.md §7.4 N5; LINUX_VM_SEMANTIC_AGENT.md) + The Rust (zbus/tokio) accessibility agent — the ax_* semantic control plane over + AF_VSOCK port 2036. A systemd USER service inside the graphical session so it can + reach that session's AT-SPI a11y bus. Baked into the naros-vm desktop flavor + (pulled by naros-tier-vm-desktop); complements the static-C nucleic-linux-agent + (exec, port 2035). Absent → the host falls back to screenshot + pixel actions. diff --git a/packages/nucleic-a11y-agent/stage.sh b/packages/nucleic-a11y-agent/stage.sh new file mode 100644 index 0000000..4c522c3 --- /dev/null +++ b/packages/nucleic-a11y-agent/stage.sh @@ -0,0 +1,21 @@ +# Stage the prebuilt Rust AT-SPI semantic agent + its systemd USER unit, with a static +# global-enable symlink so it starts in every graphical session (no `systemctl --global +# enable` needed inside the mmdebstrap chroot). Prefer the CI-built dist/bin binary; fall +# back to the committed guest build (arm64) — the same artifact the pre-narOS base build bakes. +stage() { + local dest="$1" arch="$2" + local bin="$OS_DIR/dist/bin/nucleic-a11y-agent-$arch" + if [ ! -x "$bin" ] && [ "$arch" = arm64 ]; then + bin="$OS_DIR/../guest/nucleic-a11y-agent/build/nucleic-a11y-agent" + fi + local unit="$OS_DIR/../guest/nucleic-a11y-agent/systemd/nucleic-a11y-agent.service" + if [ ! -x "$bin" ]; then + echo "prebuilt binary missing: dist/bin/nucleic-a11y-agent-$arch" > "$dest/.skip-reason" + return 1 + fi + install -D -m 0755 "$bin" "$dest/usr/local/bin/nucleic-a11y-agent" + install -D -m 0644 "$unit" "$dest/usr/lib/systemd/user/nucleic-a11y-agent.service" + install -d "$dest/etc/systemd/user/graphical-session.target.wants" + ln -sf /usr/lib/systemd/user/nucleic-a11y-agent.service \ + "$dest/etc/systemd/user/graphical-session.target.wants/nucleic-a11y-agent.service" +}