Watch
1
0
Fork
You've already forked souveraine
0
Commit graph

209 commits

Author SHA1 Message Date
Fimeg
a799bf1cde ci: make the upower cross build actually work
The upower steps were added after the last green release and had never
run successfully — the Jul 13 edge release contains no upower package at
all. Six defects, each hiding the next, found by reproducing the steps on
the runner:

- SOUVERAINE_AARCH64_SYSROOT was exported in the binaries step, not this
  one; steps do not share environment, so the pkg-config wrapper fell back
  to /usr/aarch64-linux-gnu and glib was not found.
- c_link_args had --sysroot but no -L, so ld could not resolve the bare
  paths inside the sysroot linker scripts (libm, libmvec).
- PKG_CONFIG_LIBDIR covered only lib/pkgconfig; udev.pc lives in
  share/pkgconfig. Fixed in the wrapper, which overrides the caller.
- introspection ran g-ir-scanner against an aarch64 build and failed;
  disabled for the cross build only (the phone ships no UPowerGlib
  typelib and quickshell's UPower module is native Qt).
- gtk-doc/man default on, but gtkdoc-scan is absent from the runner, so
  the x86_64 native build would have failed at the same point.
- the aarch64 sanity check tested usr/lib/upowerd; it installs to
  usr/libexec/upowerd, so the check failed even on a good build.

Verified on archdev: aarch64 56/56 targets, upowerd is aarch64, built
from 628283f with the charge-type fix; x86_64 58/58 native.
2026-07-24 20:55:33 -04:00
Fimeg
4d595796ac ci: re-run aarch64 packaging
The previous run raced a concurrent cargo build on the archdev runner
for the shared ~/.cargo package-cache lock and failed in 92s.
2026-07-24 20:23:22 -04:00
Fimeg
687cfeb5fb memory tests: mkdir -p before seeding fixture files
init() scaffolds only system/; the other schema roots are created on
first write by the real write path. Three tests seeded fixtures directly
into issues/, projects/ and reference/ and died on ENOENT, which failed
cargo test and skipped the packaging job that publishes the pacman repo.
2026-07-24 20:10:28 -04:00
Fimeg
336dadf006 upower: bump to 628283f (kernel spells CHARGE_TYPE_NONE as N/A)
The submodule was pinned one commit behind the fix, so every CI-built
upower-souveraine fell through to the warning path and reported
charge-type unknown while discharging.
2026-07-24 19:51:33 -04:00
Fimeg
b4b30b124d Unified device state machine + security hardening
sessiond:
- device_state.rs: 8-state unified device state machine with legal
  transition table, sensor evidence model (proximity/accel/light/touch),
  confidence scoring, cross-sensor disagreement detection, and forensic
  logging with full state snapshots at every decision point.
- protocol.rs: extended with DeviceState, SensorInput, and ForensicLog
  IPC requests. SensorSource/SensorValue types for proximity, accel,
  light, touch.
- server.rs: DeviceStateMachine integrated into Daemon struct. Handlers
  for DeviceState (full state query), SensorInput (sensor evidence +
  Observed transitions), ForensicLog (recent entries query).
- lock.rs: Failed attempt counter on PIN surface (advisory, PAM owns
  lockout policy). Rendered as red digit glyphs below PIN dots.
- draw.rs: Attempt counter rendering + test.
- auth.rs: PAM config docs reference.
- mod.rs: device_state module added.

shell:
- IdleCoordinator.qml: Legal transition table with runtime enforcement.
  setState() refuses illegal transitions with warning. returnActive()
  explicitly only allows Dimmed/Waking.
- GlobalStates.qml: Write authority comments on every property (// WRITER:).
- SessionAudit.qml: SHA-256 replaces MD5 for hash chain. Forensic event
  wiring (device-state-transition, device-error, sensor-input, wake-event).
  logDeviceError/logSensorInput/logWakeEvent functions for QML callers.

Design doc: SouveraineOS/docs/DEVICE-STATE-MACHINE.md (separate repo).

Tests: 22 passing (was 7). Full lifecycle test exercises Active → Dimmed →
Locked → Observed → DozeLight → DozeDeep → Suspending → Asleep → Locked
with 23 forensic entries.
2026-07-24 16:29:04 -04:00
Fimeg
0b13e2d347 fix: speech prefetch flag, agent identity on restore, workspace selector
Speech: prefetch() now sets synthProc._prefetch=true before voiceLookup
so the background synth doesn't auto-play. speak() skips voiceLookup
when the endpoint+voice are already resolved (faster repeat taps).

Ai: addMessage defaults model to Souveraine.currentAgentId so restored
messages (/resume, new conversations) show the agent icon/name instead
of a generic placeholder.

Session: create_with_messages_and_timestamps preserves persisted
created_at/updated_at through load_persisted so /resume sorts by
actual activity time, not server restart time.

TTS: ttsClean strips unclosed think blocks, fixes regex dotAll flag
for older Qt/V8 (phone), adds pronunciation map.

SubconsciousTicker: tap psychology icon to expand inline mini-log,
long-press to open the event panel overlay.

New: workspace-selector.sh + .desktop — wofi dmenu grid for quick
workspace 1-10 jump from the app drawer. Installed to phone via
deploy.sh symlink.
2026-07-23 16:47:00 -04:00
Fimeg
19fe6b1d0e shell: dock reorder, fullscreen detection fix, idle-power, sessiond, misc shell work
- Dock drag-to-reorder for pinned apps (insertion gap, quick-slide vs dwell)
- Fullscreen detection: scan all windows via HyprlandData.windowList
- IdleCoordinator, GlobalStates, Session.qml updates
- Deploy script, qmldir, settings, wallpaper, visualizer fixes
- sessiond server, memory module updates

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 22:18:20 -04:00
Fimeg
9ccefd6c73 dock: fix fullscreen detection — scan all windows, not just active/focused
Previous fullscreen detection had two blind spots:
1. Workspace scan used wayland?.fullscreen (unreliable) and missed qs -p windows
2. HyprlandData.activeWindow fallback only saw the focused window — missed
   fullscreen apps that lost focus to layer-shell surfaces (dock, notifications)

Now scans HyprlandData.windowList (hyprctl clients -j) for any window with
fullscreen === 2 on the focused monitor. Source of truth for all windows,
not just the active one. Reactive via HyprlandData's event-driven updates.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 21:25:08 -04:00
Fimeg
132d8134f2 dock: add drag-to-reorder for pinned apps alongside existing combine-into-stack
Dragging a pinned app now shows an insertion gap indicator when hovering
over other pinned apps. Quick horizontal slide + release = reorder the
pinned apps array. Dwell (500ms) on a target still = combine into stack
(existing behavior). Both gestures share the same drag start and ghost.

TaskbarApps: reorderPinned() splice-moves within Config.options.dock.pinnedApps.
DockApps: shared dragSourceIndex/dragInsertIndex state, delegate passes
  parent.index as modelIndex to DockAppButton.
DockAppButton: insertion indicator (2px primary-color line), DropArea
  onEntered computes gap position based on drag direction, release handler
  commits reorder when no dwell fired.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 21:11:19 -04:00
Fimeg
9c27504009 quickshell: converge live trees without root replacement 2026-07-21 19:11:51 -04:00
Fimeg
b0a1304ba1 quickshell: pin shared ii base and phone overlay 2026-07-21 18:55:02 -04:00
Fimeg
cd2150542e settings: wallpaper download + purity toggle, repo-owned
Adds a Download-random-wallpaper button and a 3-way content filter
(SFW/Sketchy/NSFW) to our Wallpaper settings page, backed by a new
WallpaperDownload service and its own download script under
surfaces/quickshell/scripts/wallpaper/ — not ii's scripts/colors tree,
which is going away. Only the 'wallpapers apply' IPC target still comes
from ii and moves with it when the base is vendored.

Downloads are named by wallhaven id so the library accumulates instead of
overwriting a single wallhaven_wallpaper.<ext>. Purity is read from and
written to background.wallhaven.purity in config.json (not in the upstream
Config.options schema). Anchors the root scripts/ gitignore to / so shipped
surface scripts are tracked.
2026-07-21 17:30:32 -04:00
Fimeg
0d06cbb983 quickshell: dock fullscreen fallback via HyprlandData IPC, wallpaper folder browsing 2026-07-21 15:52:32 -04:00
Fimeg
db6d732e32 shell: regenerate qmldir manifests from the composed tree
The repo qmldirs listed only repo-owned types; composed dirs also carry
ii-borrowed types (ReloadPopup, PanelLoader, Bar, ...) which a qmldir
present in the dir must list or they stop resolving — broke the phone
shell on deploy. Regenerated every deployed qmldir from the composed
config on-device (capitalized .qml -> type line, pragma Singleton ->
singleton line) and pulled back. Shell verified active, zero load
errors.
2026-07-21 13:36:39 -04:00
Fimeg
acc1161e71 shell: Speech service + sidebar Speak button (Read Aloud seam)
Speech.qml singleton: speak(text) reads the who->voice mapping live
from souveraine /v1/config (VoiceConfig tts_url + voice_id), POSTs
VibeVoice /audio/speech ({input, voice, model} -> mp3, same contract
as core/voice/client.rs) and plays via mpv/ffplay. The shell picks no
voice of its own. speech.tts.enable is the kill switch (button hidden
when off); speech.tts.endpoint overrides the mapped URL. Sidebar gains
a volume_up/stop toggle beside send that reads the last visible
assistant reply, skipping lock-redacted content.
2026-07-21 13:28:47 -04:00
Fimeg
7e74ce37e3 shell: carry all qmldir manifests through deploy compose
deploy.sh recomposes ~/.config/quickshell/souveraine with rm -rf each
run; the 19 new qmldir files were hand-placed on the phone and would
be wiped on next deploy. Add them to the manifest.
2026-07-21 13:05:41 -04:00
Fimeg
271e4f2cc2 shell: add missing qmldir manifests + rail OSK layer fix
19 dirs had .qml but no qmldir -> quickshell config load failed
(File not found @ shell.qml[-1:-1]). Corrected singleton decls in
3 existing qmldir. SystemGestureRail: pill->WlrLayer.Top, oskLift
200, drop oskOpen hide.
2026-07-21 13:01:58 -04:00
Fimeg
5e5bf0437c rail: hide while the OSK is up
Floating the pill atop the keyboard stole top-row taps and stacked over
stevia's upward-opening layout menu. 3-finger swipe / stevia's menu
cover dismissal while typing.
2026-07-21 10:13:24 -04:00
Fimeg
402e887dfc settings: Speech page — STT/TTS endpoints with live health probe
speech.stt/speech.tts land in Config so the settings page, the
souveraine-stt CLI, and the keyboard mic key all read one source of
truth. STT defaults to the VPN faster-whisper bridge; the page probes
/health so configured and answering are visibly different states. TTS
is a field waiting for a server.
2026-07-21 09:58:09 -04:00
Fimeg
ad5be0a661 crash reporter: surface crashes.log, failed units, coredumps through the notify pipe 2026-07-21 08:40:00 -04:00
Fimeg
90077bb1ea lock: notifications card + NotifyEvents fan-out seam, battery fraction fix 2026-07-21 08:17:54 -04:00
Fimeg
5083954c38 lock: own backdrop with wallpaper option, am/pm clock
The session-lock surface was transparent with nothing painting behind it.
TouchLockSurface now owns its backdrop: lock.wallpaperPath when pinned,
else the system wallpaper, else a dark field — plus a scrim for glance
legibility. Glance clock gains lock.twelveHourClock (default on, h:mm ap).
LockConfig grows the wallpaper picker (same FolderListModel grid as the
wallpaper page, no matugen side effects) and the 12-hour switch.
2026-07-20 22:47:11 -04:00
Fimeg
d824ca7f81 secrets: at-rest encryption, passphrase wrap, phone packaging
Seal items AES-256-GCM under a random store key (item id as AAD).
Machine wrap: HKDF over a deterministic machined signature (domain
secrets-store-key, socket /run/souveraine/machined.sock; legacy
seed-id fallback, same framing) — private key never enters the daemon.
Argon2id passphrase wrap slot (64MiB/3, HKDF-mixed with the machine
signature) managed via org.souveraine.Secrets.Manage: SetPassphrase /
VerifyPassphrase / HasPassphrase; rotation re-wraps only.

Client-found spec fixes: DH prime was the 2048-bit group-14 constant,
not the 1024-bit Second Oakley group libsecret uses (pinned by test);
item ids now simple UUIDs (hyphens illegal in object paths); collection
also served at /aliases/default; interfaces registered before name
claim. Added spec signals, real timestamps, content types, atomic 0600
store writes.

packaging: systemd user unit, D-Bus activation shadow, idempotent
phone deploy script (masks gnome-keyring, verifies round-trip).
2026-07-20 21:16:32 -04:00
Fimeg
d027251024 session: use systemctl for power verbs, not loginctl
loginctl manages sessions/users/seats only — `loginctl poweroff` exits 1
"Unknown command verb". Preferring it silently broke poweroff/reboot/
suspend/hibernate from every shell surface. Use systemctl; fall back to
loginctl only on elogind systems where it does carry power verbs. The
logind D-Bus capability probe (CanPowerOff etc.) is unchanged — logind
owns policy, systemctl carries out the action.
2026-07-20 17:51:30 -04:00
Fimeg
e3cf50bf75 quickshell: boot bloom overlay + native pipewire audio
The C splash now plays only Acts I-III and hands off at ~6.8s; a new
BootBloom layershell overlay (modules/souveraine/boot) resumes Acts IV-V
(Souvie + bloom flower) over the live compositor, clock-aligned to the boot
epoch so the animation is continuous across the process swap. It maps as
Hyprland's first surface (top-level in ShellRoot, before Config.ready),
pokes splash-signal on its first frame to release the GPU, and LockScreen
clears bootBloomActive on secure to fade it out and reveal the lock. Bloom
shader is qsb-compiled from BootBloom.frag at deploy time.

Drop services/Audio.qml from the manifest: it was a pactl mirror written
for native PulseAudio and only tracked the default sink/source. The phone
runs PipeWire now, so ii's native Pipewire Audio service (full graph,
WirePlumber-owned volume) takes over.
2026-07-20 17:51:23 -04:00
Fimeg
a2320641a3 restore LockContext.qml (recovered from live phone deploy)
Deleted from repo in a prior session while reverting an experiment;
never should have removed a file that wasn't reverted alongside it.
Pulled back from the phone's live ~/.config/quickshell deploy, which
was still running the correct version the whole time.
2026-07-20 07:58:35 -04:00
Fimeg
3837698c8b osk: mirror squeekboard's real Visible back into oskOpen
squeekboard auto-shows/hides itself on input-method focus without
telling the shell; the stale flag left the dock suppressed and the rail
floating at keyboard height. gdbus monitor on its Visible property is
the single truth now.
2026-07-19 22:46:09 -04:00
Fimeg
47858d5b06 phone: wallpaper picker settings page, drag-follow PIN reveal
Wallpaper grid in the settings app applying through the shell's
wallpapers IPC. Lock pad now tracks the finger during the swipe and
settles on release instead of snapping at a threshold.
2026-07-19 22:46:01 -04:00
Fimeg
7a052d77b0 task docs: lock primitives, settings authority, native audio privacy 2026-07-19 22:13:40 -04:00
Fimeg
5cb1be06cd lock primitives: power-from-lock, login1 polkit rule, gesture rail progress
seat0-active polkit rule so power off/reboot/suspend stop returning
challenge into a session with no polkit agent on the lock surface.
Lock-surface buttons stay gated behind allowPowerFromLock (opt-in) and
requirePasswordToPower. SystemGestureRail progressive gesture + mission
control nav flag.
2026-07-19 22:13:08 -04:00
Fimeg
8d661d2352 extract music player deps - souveraine-player is its own crate now 2026-07-19 22:11:33 -04:00
Fimeg
dfd494c5f1 quickshell: complete native PulseAudio source support 2026-07-18 15:05:17 -04:00
Fimeg
63a39ab5d0 upower fork: submodule, prebuilt packaging, CI build, lock-surface charge state
- packaging/upower-souveraine submodule pinned at fork head (f18b1a4,
  souveraine/charge-type): ChargeType + PercentageTrusted on Device
- PKGBUILD.upower.prebuilt: prebuilt meson install tree, provides/
  conflicts upower, replaces stock (IgnorePkg=upower on the phone)
- ci.yml: build the fork per-arch against the aarch64 sysroot, assert
  binary arch, fold into the souveraine-{arch} pacman db
- LockSurfaceHost: charge line driven by device state, not onBattery —
  no more eternal 'Charging N%' on a topped-off pack
- docs/tasks/power-indication.md force-added past the docs/ gitignore
2026-07-17 16:33:37 -04:00
Fimeg
c91c3a7796 sessiond: quiet fallback until first input, dismissnotify on handoff
fallback surface renders only the dark field until touched, so a normal
boot no longer flashes a second PIN style under the shell lockscreen.
hyprctl dismissnotify fires once the shell confirms its lock, clearing
the bogus lockscreen-crashed banner from the handoff connection drop.
2026-07-17 10:48:06 -04:00
Fimeg
401a6609ea lock: glance-first touch surface, keypad behind swipe-to-unlock
PIN pad hidden until swipe up / tap hint / hardware key; retreats after
25s idle with nothing typed. shouldReFocus no longer implies reveal --
hypridle fires it on every wake and wake must land on glance.
2026-07-17 06:46:49 -04:00
Fimeg
4fe27d9ef5 lock: resync screenLocked when compositor ends our lock
ext-session-lock finished (another client held the lock) drops
WlSessionLock.locked C++-side; the request bool never heard about it.
Stale true lied to redaction/capability gates and blocked re-locking
(the binding only fires on a false->true edge).
2026-07-17 06:17:53 -04:00
Fimeg
50530b1159 fix lock feedback loop + impatient sessiond boot lock
Session.lock() notified logind unconditionally; hypridle's lock_cmd fires
on logind's Lock signal, so every lock echoed back through logind ->
hypridle -> lock() forever. Observed: ~450 lock requests/min for 7 minutes,
re-locking the screen seconds after each unlock. Notify only on the
unlocked->locked edge.

sessiond gave up waiting for the compositor lock ack after one dispatch —
at boot Hyprland defers the ack while the splash holds DRM, so the initial
lock silently failed (journal: 'never acknowledged', 0.7s in) and boot ran
on the legacy lock path. Wait up to 60s for locked/finished.
2026-07-17 06:01:36 -04:00
Fimeg
9254333fcc sessiond bridge: use connectionStateChanged, fix lock card imports
The shell refused to load on the phone — onSocketConnected/
onSocketDisconnected handler-slots aren't reliably attachable across
quickshell builds, so the whole singleton cascade aborted at the bridge.
Switched to the real connectionStateChanged signal, branching on
sock.connected. LockAgentCard needs 'import qs' for the GlobalStates
singleton (root module), not just qs.services.
2026-07-16 21:32:43 -04:00
Fimeg
e10efbbd56 lock surface: restore redacted chat on unlock + announce replies
Redacted messages stayed '[content hidden until unlock]' forever — nothing
restored them on unlock. Redaction now records the message and unlock
restores content from rawContent. Turns finishing while locked are also
redacted and surfaced. New LockAgentCard shows a one-line preview of
replies that landed during the lock window on the lock glance, like a
notification; body stays hidden until unlock.

sessiond auth: getpwuid_r buffer is u8 with a c_char cast so it compiles
on aarch64 (c_char = u8 there) and x86 (c_char = i8).
2026-07-16 21:16:28 -04:00
Fimeg
dc9fe900ec conversation seeding + memfs frontmatter fixes
API-created conversations (shell /agent, /new) never got a system prompt —
the agent booted amnesiac with no constitution, memories, or skills. Prompt
seeding now lives on SouveraineServer and every entry point shares it.

Memory frontmatter: stop serializing None as 'key: null', round-trip
unknown keys instead of destroying them, merge agent-supplied frontmatter
instead of nesting a second block in the body, and make reads tolerant so
a nonconforming file can still be read and healed.
2026-07-16 20:57:41 -04:00
Fimeg
856c6e5576 sessiond: session authority daemon — lock-before-shell, lock-past-shell-death
ext-session-lock client that locks at session start, hands the lock to the
shell over a runtime socket without an unlocked instant (abandon + restore),
and retakes it the moment the shell heartbeat drops. Spartan PIN fallback
surface, PAM via hand-rolled libpam FFI, machined-style sync server.
Shell side: SessiondBridge singleton + LockScreen initIfReady routes the
startup lock decision through the handshake.
2026-07-16 20:32:46 -04:00
Fimeg
b18fa331e0 idle: wire the dim stage and native-coordinator hardening
Dimmed now actually lowers the backlight (brightnessctl save/restore)
and Active restores it - previously dimRequested had no consumer, so
auto-dim never existed on this stack. Keep System Awake is checked
inside the monitor handlers rather than bound to enabled: recreating
the ext-idle-notify object during lock teardown is a fatal Wayland
protocol error on the Pixel compositor. Defaults now mirror the
hypridle timers (dim 120s, lock 300s).
2026-07-16 17:44:01 -04:00
Fimeg
b4dc39e501 parse reasoning_content alias (deepseek/z.ai reasoning field name) 2026-07-16 13:03:51 -04:00
Fimeg
33068d69ff turn errors reach every surface: Error event end-to-end, no more silent empty replies 2026-07-16 12:55:49 -04:00
Fimeg
da410b1e6a hosted agents: read seeds from the live agents tree, not server/agents 2026-07-16 12:20:56 -04:00
Fimeg
c96f95b9da quickshell: fix drag-to-combine, rail rides the keyboard, overview gap-tap dismiss
The drag ghost was anchored (centerIn) — Qt won't move an anchored
drag.target, so no DropArea ever fired and stack creation died silently;
position it on press instead. Drag lifecycle now sets dockDragInProgress
(the DockManifest guard finally has a writer). Restored pulseDockReveal,
lost in a refactor while its osk.pulseDock caller survived.

Rail lifts atop squeekboard by measured layer height (hyprctl -j layers,
namespace osk); swipe down dismisses the keyboard first, then a visible
dock in any state (new dockSuppressed, cleared by swipe up). Overview:
taps in the grid's dead space dismiss it instead of being eaten.
DockConfig grew the real pins/stacks editor (unpin, rename, unstack,
dissolve).
2026-07-16 12:04:08 -04:00
Fimeg
8e540c773d instance awareness: device_announce carries hosted_agents
The full server's bridge now announces which agent pubkeys this box
hosts (read fresh per reconnect), same list the lite listener already
computed — loader moved to federation/mod.rs and shared. DeviceRegistry
records it (serde default keeps old known_peers.json parsing) and
souveraine peers shows a hosts: line. Durable memfs-side instance log
still to come.
2026-07-16 11:17:47 -04:00
Fimeg
a62379ad8a memory sync: manual push/fetch against the shared memfs remote
Per-instance branch (instance/{machine-pubkey-prefix} until commission
labels exist) on the origin remote. Fetch + push only — never touches
the working tree; merge policy is the next step. Shells out to system
git so creds work like everywhere else. Loud without a remote;
provisioning stays explicit.
2026-07-16 11:11:49 -04:00
Fimeg
8cfa992da2 memfs_commit presence signal on the bus after memory mutations
One event per memfs write/append/delete, replacing the three bespoke
memory_* events nobody consumed. Payload carries op, agent pubkey (seed
beside memfs), machine instance (machined-first), paths, head commit,
branch — enough for a federated peer to know to fetch. Best-effort:
missing identity warns and ships null, never blocks the write.
MemoryRepo stays a pure store; grew head_commit_hex/current_branch.
2026-07-16 11:07:32 -04:00
Fimeg
116562a615 machined: MachineSigner — server signs as the machine without holding the key
All machine-seed consumers now resolve identity machined-first with a
loud legacy fallback, and none of them generate. Federation envelopes
are signed through MachineSigner with domain separation
(souveraine-machined:v1:federation-envelope:...) so the wire format is
identical whichever tier holds the key; verify reconstructs the same
frame. Unsignable events are dropped loudly, never sent unsigned.
identity show/sign are load-only now — reading an identity must not
mint one. Round-trip + tamper tests on the envelope.
2026-07-16 10:24:14 -04:00