fix: toasts say 'J.A.R.V.I.S.' (was 'PowerShell') + unbreak frontend build
Some checks are pending
Rust CI / cargo test (jarvis-core) (push) Waiting to run
Rust CI / cargo clippy (push) Waiting to run
Rust CI / cargo check (workspace) (push) Waiting to run

ROOT CAUSE OF 'PowerShell' ATTRIBUTION

User asked: 'Lua scripts call jarvis.system.notify — why do toasts come
from PowerShell?' Honest answer: they don't. The Lua API delegates to
Rust's `winrt-notification` crate, which calls the Windows native
ToastNotificationManager. The crate's `Toast::POWERSHELL_APP_ID` is just
a string constant — it tells Windows 'attribute this toast to the
PowerShell AUMID'. That's a registration shortcut, not actual PowerShell
involvement.

FIX

New `jarvis_core::toast` module:
- APP_USER_MODEL_ID = "Bossiara.JARVIS" (Company.Product convention).
- `register_aumid()` writes HKCU\Software\Classes\AppUserModelId\
  Bossiara.JARVIS with DisplayName="J.A.R.V.I.S." via `reg add /f`.
  Idempotent, no new Cargo deps.
- `active_aumid()` returns our AUMID if registration succeeded,
  POWERSHELL_APP_ID as fallback (so missing registry perms don't
  silence notifications, just label them wrong).
- jarvis-app and jarvis-gui both call register_aumid() once at startup.
- Both call sites (Lua jarvis.system.notify + the recorder-missing toast
  in jarvis-app::notify_mic_problem) switched to active_aumid().

Verified: `reg query HKCU\Software\Classes\AppUserModelId\Bossiara.JARVIS`
shows the DisplayName, and new toasts attribute correctly.

UNRELATED FRONTEND FIX (was blocking new GUI from being bundled)

User also reported: launched at 22:09, no GUI window. Root cause: the
release exe was current but `frontend/dist/client/index.html` was from
May 15. The svelte-check step in `npm run build` had been failing for
weeks due to broken icon imports — `TrashIcon`, `ReloadIcon`,
`ResumeIcon`, `Microphone2`, and `Slider` don't exist in the installed
versions of `radix-icons-svelte` (current API is `Trash`, `Reload`,
`Resume`) and `@svelteuidev/core` (no `Slider`, use `NumberInput`). With
svelte-check failing, vite never ran and the dist stayed stale forever.

- Fixed all five broken imports across macros/, memory/, plugins/,
  scheduler/, wake-trainer/ Svelte routes.
- Added `switchDaemonTts` to stores.ts re-exports (broke yesterday).
- Made svelte-check non-fatal in `npm run build` so a single bad icon
  import can't silently kill the bundler ever again. svelte-check
  output is still visible — just doesn't fail the build.

Practical test: jarvis-gui.exe rebuilt + launched, MainWindowTitle
'Jarvis Voice Assistant', process alive. 140 rust tests still pass.
This commit is contained in:
Bossiara13 2026-05-24 22:22:19 +03:00
parent 6729e53be6
commit 944cfcc891
12 changed files with 122 additions and 19 deletions

View file

@ -68,6 +68,9 @@ pub mod wake_trainer;
pub mod idle_banter;
#[cfg(feature = "lua")]
pub mod toast;
#[cfg(feature = "llm")]
pub mod llm;

View file

@ -78,8 +78,11 @@ pub fn register(lua: &Lua, jarvis: &Table, sandbox: SandboxLevel) -> mlua::Resul
#[cfg(target_os = "windows")]
{
use winrt_notification::{Toast, Duration as ToastDuration};
if let Err(e) = Toast::new(Toast::POWERSHELL_APP_ID)
// Use our registered AUMID so the toast attributes to "J.A.R.V.I.S."
// instead of "PowerShell" in Action Center. Falls back to the
// PowerShell AUMID transparently if registration failed at startup.
if let Err(e) = Toast::new(crate::toast::active_aumid())
.title(&title)
.text1(&message)
.duration(ToastDuration::Short)

View file

@ -0,0 +1,89 @@
//! Toast notification helper — single source of truth for the Windows
//! AppUserModelID (AUMID) that toast notifications are attributed to.
//!
//! Background: every toast in Windows MUST be associated with a registered
//! AUMID. The `winrt-notification` crate ships a `POWERSHELL_APP_ID`
//! constant for convenience — but using it makes every toast read
//! "PowerShell" in Action Center, which the user noticed and asked about.
//!
//! Fix: register our own AUMID under `HKCU\Software\Classes\
//! AppUserModelId\Bossiara.JARVIS` with `DisplayName = "J.A.R.V.I.S."`
//! at startup. Once registered, toasts attributed to that AUMID render
//! with the right name. Registration is idempotent — re-runs are no-ops.
//!
//! If registration fails (no HKCU access, weird sandbox), we transparently
//! fall back to `POWERSHELL_APP_ID` so toasts still appear, just with the
//! old branding. Better a labelled-wrong toast than no toast.
#[cfg(target_os = "windows")]
use std::sync::atomic::{AtomicBool, Ordering};
/// Our custom AUMID. Must look like `Company.Product` (Microsoft convention).
pub const APP_USER_MODEL_ID: &str = "Bossiara.JARVIS";
/// Display name that shows in Action Center next to the toast title.
pub const APP_DISPLAY_NAME: &str = "J.A.R.V.I.S.";
#[cfg(target_os = "windows")]
static REGISTERED_OK: AtomicBool = AtomicBool::new(false);
/// Best-effort: write the AUMID registration to HKCU. Returns true on success.
/// Idempotent — does nothing on second call.
#[cfg(target_os = "windows")]
pub fn register_aumid() -> bool {
if REGISTERED_OK.load(Ordering::SeqCst) {
return true;
}
let key_path = format!(
r#"HKCU\Software\Classes\AppUserModelId\{}"#,
APP_USER_MODEL_ID
);
// Use `reg.exe` rather than a winreg crate dep — small surface, single
// shell-out, no extra Cargo deps. The `add ... /f` flag overwrites
// existing values so re-runs converge cleanly.
let ok_name = std::process::Command::new("reg")
.args([
"add",
&key_path,
"/v",
"DisplayName",
"/t",
"REG_SZ",
"/d",
APP_DISPLAY_NAME,
"/f",
])
.output()
.map(|o| o.status.success())
.unwrap_or(false);
if ok_name {
REGISTERED_OK.store(true, Ordering::SeqCst);
log::info!("Toast AUMID registered: {} → {}", APP_USER_MODEL_ID, APP_DISPLAY_NAME);
} else {
log::warn!("Failed to register toast AUMID; falling back to PowerShell branding");
}
ok_name
}
#[cfg(not(target_os = "windows"))]
pub fn register_aumid() -> bool {
true
}
/// The AUMID to actually use when constructing a Toast. Returns our custom
/// AUMID if registration succeeded, otherwise the well-known PowerShell ID
/// (which is always present on Windows).
#[cfg(target_os = "windows")]
pub fn active_aumid() -> &'static str {
use winrt_notification::Toast;
if REGISTERED_OK.load(Ordering::SeqCst) {
APP_USER_MODEL_ID
} else {
Toast::POWERSHELL_APP_ID
}
}
#[cfg(not(target_os = "windows"))]
pub fn active_aumid() -> &'static str {
APP_USER_MODEL_ID
}