feat(robin): M1 System Presence — journald/kmsg/inotify watcher, pattern classifier, tray badge, chat panel #2

Open
pyr0ball wants to merge 21 commits from feat/m1-system-presence into main
Owner

Summary

  • Adds full system event pipeline: journald, kmsg, and inotify app-log watchers feed a channel that is classified against TOML pattern files and dispatched as tray badges, desktop toasts, and IPC events
  • Ships starter pattern files for macos-to-arch (7 patterns: AUR, Proton, Steam, RetroArch, firmware, codec) and windows-to-debian (6 patterns: apt, Proton, firmware, codec, snap)
  • ChatPanel Vue component drains missed events on open, listens for live robin:event IPC, and correctly gates the PENDING queue via panel_opened/panel_closed commands to prevent double-delivery on re-open

Notable fixes applied during review

  • classify(): validates non-empty match_text and sources at load time to prevent silent always-match
  • EventSource::AppLog uses struct variant (not tuple) for serde tagged-enum compatibility
  • inotify watcher uses read_to_end + from_utf8_lossy for UTF-8 resilience on Wine/game logs
  • journald child process is properly waited after loop exit (prevents zombie)
  • Mutex poison recovery throughout (unwrap_or_default pattern)
  • PANEL_OPEN AtomicBool prevents PENDING queue accumulation while panel is active

Test Plan

  • cargo test --lib passes on CachyOS (Xander) — all unit tests in distro, patterns, notify, watcher/journald
  • npm run build passes (TypeScript + Vue — zero errors)
  • App launches, tray icon appears
  • journalctl matching: trigger a pattern (e.g. AUR build failure) and verify badge + toast appear
  • ChatPanel opens, drains pending events correctly on first open
  • Close and reopen ChatPanel: no duplicate events shown
  • With NotificationLevel::Off: no badge or toast fires, but events still appear in ChatPanel
## Summary - Adds full system event pipeline: journald, kmsg, and inotify app-log watchers feed a channel that is classified against TOML pattern files and dispatched as tray badges, desktop toasts, and IPC events - Ships starter pattern files for `macos-to-arch` (7 patterns: AUR, Proton, Steam, RetroArch, firmware, codec) and `windows-to-debian` (6 patterns: apt, Proton, firmware, codec, snap) - ChatPanel Vue component drains missed events on open, listens for live `robin:event` IPC, and correctly gates the PENDING queue via `panel_opened`/`panel_closed` commands to prevent double-delivery on re-open ## Notable fixes applied during review - `classify()`: validates non-empty `match_text` and `sources` at load time to prevent silent always-match - `EventSource::AppLog` uses struct variant (not tuple) for serde tagged-enum compatibility - inotify watcher uses `read_to_end` + `from_utf8_lossy` for UTF-8 resilience on Wine/game logs - journald child process is properly waited after loop exit (prevents zombie) - Mutex poison recovery throughout (`unwrap_or_default` pattern) - `PANEL_OPEN` AtomicBool prevents PENDING queue accumulation while panel is active ## Test Plan - [ ] `cargo test --lib` passes on CachyOS (Xander) — all unit tests in `distro`, `patterns`, `notify`, `watcher/journald` - [ ] `npm run build` passes (TypeScript + Vue — zero errors) - [ ] App launches, tray icon appears - [ ] `journalctl` matching: trigger a pattern (e.g. AUR build failure) and verify badge + toast appear - [ ] ChatPanel opens, drains pending events correctly on first open - [ ] Close and reopen ChatPanel: no duplicate events shown - [ ] With `NotificationLevel::Off`: no badge or toast fires, but events still appear in ChatPanel
pyr0ball added 21 commits 2026-05-18 23:22:57 -07:00
- parse_id now strips both double and single quotes per os-release spec
- distro_family debian arm includes "mint" (legacy Linux Mint ID)
- Add tests: single-quoted ID round-trip, mint family classification
Add EventSource enum and update SystemEvent in watcher.rs (M0 stub
updated to support Task 5 clean deletion). Create patterns.rs with
PatternFile/Pattern/MatchedEvent types, TOML loader, and classify()
matching against source + text. Five unit tests covering journald,
applog, no-match, and source discrimination cases.
- load() now rejects patterns with empty match_text or empty sources list
- EventSource derives Serialize/Deserialize with serde tag for emit() readiness
- AppLog variant changed to struct form (AppLog { app }) for tagged enum compat
- classify() takes &SystemEvent directly (top-level use import, not per-fn)
- #[must_use] on classify()
- 5 new tests: any-source wildcard (journald+kmsg), applog mismatch, empty-field validation
Replace flat watcher.rs with watcher/ module containing mod.rs plus stub
sub-modules for journald, kmsg, and inotify. Upgrades spawn() to accept
log_paths and return mpsc::Receiver<SystemEvent>. Updates lib.rs call site.
- read_to_end + from_utf8_lossy replaces read_to_string so Wine/game logs
  with Latin-1 bytes are handled via U+FFFD replacement instead of silently
  dropping all events from that file
- bytes_read from I/O call used for new_pos (not content.len()) for correct
  byte position accounting
- spawn_blocking handle is now awaited so panics inside the blocking task
  surface to the caller instead of being silently swallowed
- lib.rs: replaces stub setup with full wiring: loads PatternFile from
  config, extracts log_paths, spawns watcher, runs classifier loop in
  async task, dispatches MatchedEvents via notify::dispatch
- lib.rs: config Mutex lock uses unwrap_or_else(|e| e.into_inner()) to
  recover from poison instead of panicking
- patterns.rs: load() now tries three path candidates in order
  (dev-relative, src-tauri-relative, system) before returning bail!
  Validation loop (match_text, sources) retained inside candidate loop
pyr0ball added this to the M1: System Presence milestone 2026-05-19 07:35:45 -07:00
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/m1-system-presence:feat/m1-system-presence
git checkout feat/m1-system-presence

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git checkout main
git merge --no-ff feat/m1-system-presence
git checkout feat/m1-system-presence
git rebase main
git checkout main
git merge --ff-only feat/m1-system-presence
git checkout feat/m1-system-presence
git rebase main
git checkout main
git merge --no-ff feat/m1-system-presence
git checkout main
git merge --squash feat/m1-system-presence
git checkout main
git merge --ff-only feat/m1-system-presence
git checkout main
git merge feat/m1-system-presence
git push origin main
Sign in to join this conversation.
No reviewers
No labels
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Circuit-Forge/robin#2
No description provided.