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

@ -8,7 +8,7 @@
import {
Button, Space, Text, Notification, Badge, TextInput, Loader,
} from "@svelteuidev/core"
import { Play, TrashIcon, Plus, CrossCircled } from "radix-icons-svelte"
import { Play, Trash, Plus, CrossCircled } from "radix-icons-svelte"
interface MacroInfo {
name: string
@ -212,7 +212,7 @@
color="red" radius="md" size="xs" uppercase
on:click={() => deleteMacro(m.name)}
>
<TrashIcon size={14} /> &nbsp; Удалить
<Trash size={14} /> &nbsp; Удалить
</Button>
</div>
</div>

View file

@ -8,7 +8,7 @@
import {
Button, Space, Text, Notification, Badge, TextInput, Loader, Textarea,
} from "@svelteuidev/core"
import { Plus, TrashIcon, CrossCircled, MagnifyingGlass } from "radix-icons-svelte"
import { Plus, Trash, CrossCircled, MagnifyingGlass } from "radix-icons-svelte"
interface MemoryFact {
key: string
@ -153,7 +153,7 @@
color="red" radius="md" size="xs" uppercase
on:click={() => deleteFact(fact.key)}
>
<TrashIcon size={14} /> &nbsp; Забыть
<Trash size={14} /> &nbsp; Забыть
</Button>
</div>
</div>

View file

@ -8,7 +8,7 @@
import {
Button, Space, Text, Notification, Badge, Loader, Switch,
} from "@svelteuidev/core"
import { CrossCircled, ExternalLink, ReloadIcon } from "radix-icons-svelte"
import { CrossCircled, ExternalLink, Reload } from "radix-icons-svelte"
interface PluginEntry {
name: string
@ -82,7 +82,7 @@
</Button>
&nbsp;
<Button color="gray" radius="md" size="sm" on:click={load}>
<ReloadIcon size={14} /> &nbsp; Обновить список
<Reload size={14} /> &nbsp; Обновить список
</Button>
</div>

View file

@ -8,7 +8,7 @@
import {
Button, Space, Text, Notification, Badge, Loader,
} from "@svelteuidev/core"
import { Clock, TrashIcon, CrossCircled } from "radix-icons-svelte"
import { Clock, Trash, CrossCircled } from "radix-icons-svelte"
interface ScheduledTaskInfo {
id: string
@ -141,7 +141,7 @@
color="red" radius="md" size="xs" uppercase
on:click={() => removeTask(task.id, task.name)}
>
<TrashIcon size={14} /> &nbsp; Отменить
<Trash size={14} /> &nbsp; Отменить
</Button>
</div>
</div>

View file

@ -6,9 +6,9 @@
import HDivider from "@/components/elements/HDivider.svelte"
import Footer from "@/components/Footer.svelte"
import {
Button, Space, Text, Notification, Badge, Loader, TextInput, NumberInput, Slider,
Button, Space, Text, Notification, Badge, Loader, TextInput, NumberInput,
} from "@svelteuidev/core"
import { CrossCircled, Microphone2, TrashIcon, Check, ResumeIcon } from "radix-icons-svelte"
import { CrossCircled, SpeakerLoud, Trash, Check, Resume } from "radix-icons-svelte"
interface TrainerStatus {
recording: boolean
@ -195,11 +195,11 @@
<Space h="sm" />
<div class="row">
<Text size="xs">Длина сэмпла: {sampleSeconds.toFixed(1)} сек</Text>
<Slider min={0.8} max={3.0} step={0.1} bind:value={sampleSeconds} disabled={busy} />
<NumberInput min={0.8} max={3.0} step={0.1} bind:value={sampleSeconds} disabled={busy} />
</div>
<Space h="sm" />
<Button color="lime" radius="md" size="sm" disabled={busy} on:click={recordOne}>
<Microphone2 size={14} /> &nbsp;
<SpeakerLoud size={14} /> &nbsp;
{busy ? "Запись..." : `Записать сэмпл (${status.collected + 1})`}
</Button>
&nbsp;
@ -211,7 +211,7 @@
<Space h="md" />
<div class="row">
<Text size="xs">Порог детектора: {threshold.toFixed(2)}</Text>
<Slider min={0.30} max={0.90} step={0.05} bind:value={threshold} disabled={busy} />
<NumberInput min={0.30} max={0.90} step={0.05} bind:value={threshold} disabled={busy} />
</div>
<Text size="xs" color="gray">
Ниже — больше срабатываний (и ложных). Выше — пропусков больше.
@ -242,7 +242,7 @@
/>
<Space h="sm" />
<Button color="lime" radius="md" size="sm" disabled={busy || daemonRunning} on:click={startSession}>
<ResumeIcon size={14} /> &nbsp; Начать запись
<Resume size={14} /> &nbsp; Начать запись
</Button>
</div>
{/if}
@ -264,7 +264,7 @@
<Text size="xs" color="gray">обновлено: {fmtDate(m.modified)}</Text>
<Space h="xs" />
<Button color="red" radius="md" size="xs" uppercase on:click={() => deleteModel(m.name)}>
<TrashIcon size={12} /> &nbsp; Удалить
<Trash size={12} /> &nbsp; Удалить
</Button>
</div>
{/each}

View file

@ -20,6 +20,7 @@ export {
reloadCommands,
switchDaemonLlm,
reloadDaemonLlm,
switchDaemonTts,
queryDaemonHealth,
} from "./lib/ipc"