chore: rebrand from Kon/Corbie to Magnotia

Replace all instances of the legacy product names "Kon" and "Corbie" with
"Magnotia" across user-facing copy, code identifiers, package names, bundle
ids, file paths, and documentation. Preserves the unrelated "konsole" (KDE
terminal) reference and the parent CORBEL company name.

- Renames 10 Rust crates (kon-* → magnotia-*) and the tauri binary
- Updates package.json, tauri.conf.json (productName + identifier)
- Renames CSS classes (kon-rh-* → magnotia-rh-*) and animations
- Renames brand and roadmap docs
- Regenerates Cargo.lock and package-lock.json

Verified: svelte-check passes; pure-rust crates compile under new names.
This commit is contained in:
Claude
2026-04-30 13:06:55 +00:00
parent 749403697a
commit 89c63891fa
186 changed files with 1297 additions and 1297 deletions

View File

@@ -47,17 +47,17 @@
<div class="flex items-center {collapsed ? 'justify-center px-0 pt-4 pb-1' : 'px-5 pt-4 pb-1'} relative">
{#if !collapsed}
<div class="flex items-center gap-2 flex-1 min-w-0">
<h1 class="font-display text-[26px] text-text tracking-tight leading-none italic">Kon</h1>
<h1 class="font-display text-[26px] text-text tracking-tight leading-none italic">Magnotia</h1>
<span
class="text-[18px] text-accent inline-block {page.recording ? 'animate-sinhala-spin' : ''}"
title="Kon"
title="Magnotia"
>&#3559;</span>
</div>
{:else}
<!-- Collapsed: just the decorative character centred -->
<span
class="text-[18px] text-accent inline-block {page.recording ? 'animate-sinhala-spin' : ''}"
title="Kon"
title="Magnotia"
>&#3559;</span>
{/if}
</div>

View File

@@ -5,7 +5,7 @@
// centre. Completion plays a gentle chime, flashes a success ring
// for 3 s, then disappears. Cancel button appears on hover.
//
// Mounted once in +layout.svelte. Listens for `kon:start-timer`
// Mounted once in +layout.svelte. Listens for `magnotia:start-timer`
// events from anywhere in the app (e.g. MicroSteps) and delegates
// to the focus-timer store.
//
@@ -63,7 +63,7 @@
return "var(--color-accent)";
});
// Event handler: start a timer when any component fires `kon:start-timer`.
// Event handler: start a timer when any component fires `magnotia:start-timer`.
// Payload shape from MicroSteps.svelte and task row buttons:
// { taskId?: string, seconds: number, label?: string }
function handleStartEvent(evt: Event) {
@@ -77,13 +77,13 @@
}
onMount(() => {
window.addEventListener("kon:start-timer", handleStartEvent);
window.addEventListener("magnotia:start-timer", handleStartEvent);
// Rehydrate any in-flight timer that survived a window close.
focusTimer.rehydrate();
});
onDestroy(() => {
window.removeEventListener("kon:start-timer", handleStartEvent);
window.removeEventListener("magnotia:start-timer", handleStartEvent);
});
function handleCancel() {

View File

@@ -26,7 +26,7 @@
]);
// Map KeyboardEvent.code (physical key, layout-independent, shift-independent)
// to the unshifted name the kon-hotkey evdev parser understands. Browser
// to the unshifted name the magnotia-hotkey evdev parser understands. Browser
// e.key returns "+" for Shift+Equal — parser wants "=". Same for | → \, etc.
const codeToParserKey: Record<string, string> = {
Equal: "=", Minus: "-",

View File

@@ -58,7 +58,7 @@
// is completed in that window, a gentle "still with that one?"
// nudge fires.
if (typeof window !== 'undefined') {
window.dispatchEvent(new CustomEvent('kon:microstep-generated', {
window.dispatchEvent(new CustomEvent('magnotia:microstep-generated', {
detail: { parentTaskId },
}));
}
@@ -78,7 +78,7 @@
// micro-step-idle timer for this parent task — the breakdown
// is demonstrably getting worked, no nudge needed.
if (typeof window !== 'undefined') {
window.dispatchEvent(new CustomEvent('kon:step-completed', {
window.dispatchEvent(new CustomEvent('magnotia:step-completed', {
detail: { id: subtaskId, parentTaskId },
}));
}
@@ -86,7 +86,7 @@
}
function startTimer(subtaskId: string) {
window.dispatchEvent(new CustomEvent('kon:start-timer', {
window.dispatchEvent(new CustomEvent('magnotia:start-timer', {
detail: { taskId: subtaskId, seconds: 120 }
}));
}

View File

@@ -72,7 +72,7 @@
<h3 class="text-[18px] font-semibold text-text mb-2">Download Whisper Model</h3>
<p class="text-[13px] text-text-secondary mb-1">
Kon needs the <span class="font-medium text-text">{modelSize}</span> model to transcribe speech.
Magnotia needs the <span class="font-medium text-text">{modelSize}</span> model to transcribe speech.
</p>
<p class="text-[11px] text-text-tertiary mb-6">
{currentModelInfo?.size ?? "?"} · {currentModelInfo?.accuracy ?? "?"} accuracy · 100% offline

View File

@@ -67,7 +67,7 @@
function dispatchTriageFinished(mode: 'empty' | 'skipped' | 'picked') {
if (typeof window === 'undefined') return;
window.dispatchEvent(new CustomEvent('kon:morning-triage-finished', {
window.dispatchEvent(new CustomEvent('magnotia:morning-triage-finished', {
detail: { date: todayKey(), mode },
}));
}

View File

@@ -1,6 +1,6 @@
<script lang="ts">
// Invisible resize-handle overlays around each Kon window edge.
// Needed because Kon runs with decorations off, so the WM
// Invisible resize-handle overlays around each Magnotia window edge.
// Needed because Magnotia runs with decorations off, so the WM
// provides no resize affordance on KDE/GNOME Wayland.
//
// Architecture: eight fixed-position divs are the click target for
@@ -10,9 +10,9 @@
// a window move. This gives us a clean separation: resize wins on
// the edges, drag wins on the titlebar.
//
// Hit zone sizes come from CSS custom properties so every Kon window
// across the app stays identical. See the kon-resize-edge and
// kon-resize-corner custom properties in app.css.
// Hit zone sizes come from CSS custom properties so every Magnotia window
// across the app stays identical. See the magnotia-resize-edge and
// magnotia-resize-corner custom properties in app.css.
//
// Placement requirement: instances of this component MUST be mounted
// as a sibling of the animated/transformed layout root (not a child),
@@ -48,20 +48,20 @@
{#if enabled}
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="kon-rh kon-rh-n" onpointerdown={(e) => startResize(e,"North")}></div>
<div class="magnotia-rh magnotia-rh-n" onpointerdown={(e) => startResize(e,"North")}></div>
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="kon-rh kon-rh-s" onpointerdown={(e) => startResize(e,"South")}></div>
<div class="magnotia-rh magnotia-rh-s" onpointerdown={(e) => startResize(e,"South")}></div>
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="kon-rh kon-rh-w" onpointerdown={(e) => startResize(e,"West")}></div>
<div class="magnotia-rh magnotia-rh-w" onpointerdown={(e) => startResize(e,"West")}></div>
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="kon-rh kon-rh-e" onpointerdown={(e) => startResize(e,"East")}></div>
<div class="magnotia-rh magnotia-rh-e" onpointerdown={(e) => startResize(e,"East")}></div>
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="kon-rh kon-rh-nw" onpointerdown={(e) => startResize(e,"NorthWest")}></div>
<div class="magnotia-rh magnotia-rh-nw" onpointerdown={(e) => startResize(e,"NorthWest")}></div>
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="kon-rh kon-rh-ne" onpointerdown={(e) => startResize(e,"NorthEast")}></div>
<div class="magnotia-rh magnotia-rh-ne" onpointerdown={(e) => startResize(e,"NorthEast")}></div>
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="kon-rh kon-rh-sw" onpointerdown={(e) => startResize(e,"SouthWest")}></div>
<div class="magnotia-rh magnotia-rh-sw" onpointerdown={(e) => startResize(e,"SouthWest")}></div>
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="kon-rh kon-rh-se" onpointerdown={(e) => startResize(e,"SouthEast")}></div>
<div class="magnotia-rh magnotia-rh-se" onpointerdown={(e) => startResize(e,"SouthEast")}></div>
{/if}

View File

@@ -5,7 +5,7 @@
import { ChevronDown, ChevronRight, Timer } from 'lucide-svelte';
function startFocusTimer(task: { id: string; text: string }) {
window.dispatchEvent(new CustomEvent('kon:start-timer', {
window.dispatchEvent(new CustomEvent('magnotia:start-timer', {
detail: { taskId: task.id, seconds: 300, label: task.text }
}));
}

View File

@@ -19,7 +19,7 @@ export const SUPPORTED_LOCALES: { code: Locale; label: string }[] = [
{ code: "de", label: "Deutsch" },
];
const STORAGE_KEY = "kon_locale";
const STORAGE_KEY = "magnotia_locale";
register("en", () => import("./locales/en.json"));
register("es", () => import("./locales/es.json"));

View File

@@ -2,7 +2,7 @@
"settings": {
"title": "Einstellungen",
"language": "Sprache",
"languageDescription": "Oberflächensprache von Kon. Wirkt sich nicht auf die Transkription aus."
"languageDescription": "Oberflächensprache von Magnotia. Wirkt sich nicht auf die Transkription aus."
},
"history": {
"title": "Verlauf",

View File

@@ -2,7 +2,7 @@
"settings": {
"title": "Settings",
"language": "Language",
"languageDescription": "Kon's interface language. Affects labels, not transcription."
"languageDescription": "Magnotia's interface language. Affects labels, not transcription."
},
"history": {
"title": "History",

View File

@@ -2,7 +2,7 @@
"settings": {
"title": "Ajustes",
"language": "Idioma",
"languageDescription": "Idioma de la interfaz de Kon. No afecta a la transcripción."
"languageDescription": "Idioma de la interfaz de Magnotia. No afecta a la transcripción."
},
"history": {
"title": "Historial",

View File

@@ -25,7 +25,7 @@
import { hasTauriRuntime } from '$lib/utils/runtime.js';
const prefs = getPreferences();
const tauriRuntimeAvailable = hasTauriRuntime();
const browserPreviewMessage = "You're viewing Kon in a normal browser. Local transcription only works in the Tauri desktop app window.";
const browserPreviewMessage = "You're viewing Magnotia in a normal browser. Local transcription only works in the Tauri desktop app window.";
let transcript = $state("");
let segments = $state([]);
@@ -65,7 +65,7 @@
let hotkeyHandler = () => toggleRecording();
onMount(async () => {
window.addEventListener("kon:toggle-recording", hotkeyHandler);
window.addEventListener("magnotia:toggle-recording", hotkeyHandler);
if (!tauriRuntimeAvailable) {
error = browserPreviewMessage;
@@ -77,7 +77,7 @@
});
onDestroy(() => {
window.removeEventListener("kon:toggle-recording", hotkeyHandler);
window.removeEventListener("magnotia:toggle-recording", hotkeyHandler);
clearInterval(timerInterval);
if (page.recording) {
page.recording = false;
@@ -199,7 +199,7 @@
lastLiveActivityAt = Date.now();
if (status.type === "overload" || status.type === "warning") {
liveWarning = status.message || "Kon is dropping older audio to stay responsive.";
liveWarning = status.message || "Magnotia is dropping older audio to stay responsive.";
return;
}
@@ -647,7 +647,7 @@
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `kon-${new Date().toISOString().slice(0, 10)}.${ext}`;
a.download = `magnotia-${new Date().toISOString().slice(0, 10)}.${ext}`;
a.click();
URL.revokeObjectURL(url);
}

View File

@@ -142,7 +142,7 @@
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `kon-file-${new Date().toISOString().slice(0, 10)}.${ext}`;
a.download = `magnotia-file-${new Date().toISOString().slice(0, 10)}.${ext}`;
a.click();
URL.revokeObjectURL(url);
}

View File

@@ -225,9 +225,9 @@
{:else if ritualsStep === "autostart"}
<div class="w-full max-w-md mx-auto text-center">
<Play size={32} strokeWidth={1.5} class="text-accent mx-auto mb-3" />
<h2 class="text-xl font-medium text-text">Launch Corbie at login?</h2>
<h2 class="text-xl font-medium text-text">Launch Magnotia at login?</h2>
<p class="text-sm text-text-secondary mt-3 leading-relaxed">
So Corbie is already there when you need it — especially useful if you said yes to morning triage. Uses your OS's standard autostart. No background tricks, no telemetry.
So Magnotia is already there when you need it — especially useful if you said yes to morning triage. Uses your OS's standard autostart. No background tricks, no telemetry.
</p>
<p class="text-[11px] text-text-tertiary mt-3">You can change this any time in Settings.</p>
<div class="flex items-center justify-center gap-3 mt-6">
@@ -270,7 +270,7 @@
{:else}
<div class="w-full">
<h2 class="text-2xl font-medium text-text text-center">Welcome to Kon</h2>
<h2 class="text-2xl font-medium text-text text-center">Welcome to Magnotia</h2>
<p class="text-sm text-text-secondary text-center mt-2">Press the button. Start talking. That's it.</p>
{#if error}

View File

@@ -342,12 +342,12 @@
// script.
const handoff = JSON.stringify({ id: String(item.id) });
try {
localStorage.setItem("kon_viewer_item", handoff);
localStorage.setItem("kon_viewer_mode", "view");
localStorage.setItem("magnotia_viewer_item", handoff);
localStorage.setItem("magnotia_viewer_mode", "view");
await invoke("open_viewer_window");
} catch {
localStorage.setItem("kon_viewer_item", handoff);
localStorage.setItem("kon_viewer_mode", "view");
localStorage.setItem("magnotia_viewer_item", handoff);
localStorage.setItem("magnotia_viewer_mode", "view");
window.open("/viewer", "_blank", "width=600,height=700");
}
}
@@ -509,12 +509,12 @@
// (see openViewer above for the rationale).
const handoff = JSON.stringify({ id: String(item.id) });
try {
localStorage.setItem("kon_viewer_item", handoff);
localStorage.setItem("kon_viewer_mode", "edit");
localStorage.setItem("magnotia_viewer_item", handoff);
localStorage.setItem("magnotia_viewer_mode", "edit");
await invoke("open_viewer_window");
} catch {
localStorage.setItem("kon_viewer_item", handoff);
localStorage.setItem("kon_viewer_mode", "edit");
localStorage.setItem("magnotia_viewer_item", handoff);
localStorage.setItem("magnotia_viewer_mode", "edit");
window.open("/viewer", "_blank", "width=600,height=700");
}
}

View File

@@ -675,7 +675,7 @@
async function testReadAloudVoice() {
try {
await invoke("tts_speak", {
text: "This is Corbie reading aloud.",
text: "This is Magnotia reading aloud.",
rate: settings.ttsRate,
voice: settings.ttsVoice ?? null,
});
@@ -771,7 +771,7 @@
downloadProgress = event.payload.percent || event.payload.progress || 0;
});
unlistenLlm = await listen("kon:llm-download-progress", (event) => {
unlistenLlm = await listen("magnotia:llm-download-progress", (event) => {
llmDownloadProgress = event.payload.percent || 0;
llmDownloadingModel = event.payload.modelId || llmDownloadingModel;
});
@@ -984,7 +984,7 @@
bind:value={settings.microphoneDevice}
onfocus={refreshAudioDevices}
>
<option value="">Auto (recommended) — let Kon pick the working mic</option>
<option value="">Auto (recommended) — let Magnotia pick the working mic</option>
{#each visibleAudioDevices as dev}
<option value={dev.name} disabled={dev.is_likely_monitor}>
{friendlyLabel(dev)}{#if dev.is_default && dev.name !== "default"} (system default){/if}{#if dev.is_likely_monitor} — speaker monitor, skip{/if}
@@ -1624,7 +1624,7 @@
</div>
<p class="text-[11px] text-text-tertiary mt-2">
{settings.aiTier === "off"
? "No local LLM calls. Kon falls back to the existing rule-based path."
? "No local LLM calls. Magnotia falls back to the existing rule-based path."
: settings.aiTier === "cleanup"
? "Use the local model for transcript cleanup and formatting."
: "Use the local model for cleanup, task extraction, and task breakdown."}
@@ -1871,7 +1871,7 @@
disabled={autostartSyncing}
role="switch"
aria-checked={settings.launchAtLogin}
aria-label="Launch Corbie at login"
aria-label="Launch Magnotia at login"
>
<span
class="absolute top-[3px] left-[3px] w-4 h-4 rounded-full bg-white shadow-sm
@@ -1880,9 +1880,9 @@
></span>
</button>
<div class="flex-1 min-w-0">
<p class="text-[13px] text-text leading-tight">Launch Corbie at login</p>
<p class="text-[13px] text-text leading-tight">Launch Magnotia at login</p>
<p class="text-[11px] text-text-tertiary mt-0.5 leading-snug">
So Corbie is already there at the start of the day. Uses your OS's standard autostart — no background tricks.
So Magnotia is already there at the start of the day. Uses your OS's standard autostart — no background tricks.
</p>
{#if autostartSyncing}
<p class="text-[11px] text-text-tertiary mt-1">Updating…</p>
@@ -1913,7 +1913,7 @@
<SettingsGroup title="Nudges" description="Soft notifications, capped per hour.">
<div class="animate-fade-in">
<p class="text-[11px] text-text-tertiary mb-4">
Gentle, anticipatory reminders. Capped at 3 per hour. Never fires while you're looking at Corbie.
Gentle, anticipatory reminders. Capped at 3 per hour. Never fires while you're looking at Magnotia.
</p>
<Toggle
@@ -2020,13 +2020,13 @@
/>
<Toggle
bind:checked={settings.transcriptionPreview}
label="Floating preview when Kon is unfocused"
label="Floating preview when Magnotia is unfocused"
description="Shows a small always-on-top window with the raw transcription as you dictate, then the final formatted text. Only opens when the main window is unfocused or hidden."
/>
<Toggle
bind:checked={settings.meetingAutoCapture}
label="Remind me when a meeting starts"
description="Toasts when a matching app appears in the process list. You still hit the hotkey — Kon never records on its own."
description="Toasts when a matching app appears in the process list. You still hit the hotkey — Magnotia never records on its own."
/>
{#if settings.meetingAutoCapture}
<div class="ml-[50px] mt-2 mb-1 animate-fade-in">
@@ -2201,7 +2201,7 @@
{/each}
</div>
<p class="text-[11px] text-text-tertiary mt-5">Kon v1.0 · Powered by whisper.cpp · Built by CORBEL Ltd</p>
<p class="text-[11px] text-text-tertiary mt-5">Magnotia v1.0 · Powered by whisper.cpp · Built by CORBEL Ltd</p>
<!-- Diagnostic report (privacy posture: local only until you share it) -->
<div class="mt-6 pt-5 border-t border-border-subtle">

View File

@@ -3,10 +3,10 @@
//
// Refresh triggers:
// - module load (first time)
// - kon:task-completed (from page.svelte.ts completeTask)
// - kon:step-completed (from MicroSteps.svelte)
// - kon:task-uncompleted (new event, emitted by uncompleteTask in Task 10)
// - kon:task-deleted (new event, emitted by deleteTask in Task 10)
// - magnotia:task-completed (from page.svelte.ts completeTask)
// - magnotia:step-completed (from MicroSteps.svelte)
// - magnotia:task-uncompleted (new event, emitted by uncompleteTask in Task 10)
// - magnotia:task-deleted (new event, emitted by deleteTask in Task 10)
// - window focus (for day rollover while the app stayed open
// past midnight)
//
@@ -47,10 +47,10 @@ if (typeof window !== "undefined") {
const handler = () => {
refresh().catch(() => {});
};
window.addEventListener("kon:task-completed", handler);
window.addEventListener("kon:step-completed", handler);
window.addEventListener("kon:task-uncompleted", handler);
window.addEventListener("kon:task-deleted", handler);
window.addEventListener("magnotia:task-completed", handler);
window.addEventListener("magnotia:step-completed", handler);
window.addEventListener("magnotia:task-uncompleted", handler);
window.addEventListener("magnotia:task-deleted", handler);
window.addEventListener("focus", handler);
if (hasTauriRuntime()) {

View File

@@ -12,7 +12,7 @@
// so closing the window mid-timer still gets you the "done" signal
// on next launch.
const STORAGE_KEY = "kon.focusTimer.v1";
const STORAGE_KEY = "magnotia.focusTimer.v1";
const TICK_INTERVAL_MS = 250;
export type FocusTimerPersisted = {
@@ -114,7 +114,7 @@ function createFocusTimerStore() {
writePersisted(null);
stopTick();
if (wasActive && typeof window !== "undefined") {
window.dispatchEvent(new CustomEvent("kon:focus-timer-cancelled"));
window.dispatchEvent(new CustomEvent("magnotia:focus-timer-cancelled"));
}
}
@@ -172,7 +172,7 @@ function createFocusTimerStore() {
osc.onended = () => ctx.close().catch(() => {});
} catch { /* audio is a nicety; never fatal */ }
window.dispatchEvent(new CustomEvent("kon:focus-timer-complete", {
window.dispatchEvent(new CustomEvent("magnotia:focus-timer-complete", {
detail: { taskId, label },
}));
}

View File

@@ -13,7 +13,7 @@ import { page, settings, tasks } from "$lib/stores/page.svelte.js";
import { toasts } from "$lib/stores/toasts.svelte.js";
const TIME_RULE_POLL_MS = 30_000;
const RULES_CHANGED_EVENT = "kon:implementation-rules-changed";
const RULES_CHANGED_EVENT = "magnotia:implementation-rules-changed";
export const implementationRules = $state<ImplementationRule[]>([]);
@@ -157,7 +157,7 @@ async function executeAction(action: ImplementationRuleAction): Promise<void> {
return;
}
if (action.kind === "start_timer") {
window.dispatchEvent(new CustomEvent("kon:start-timer", {
window.dispatchEvent(new CustomEvent("magnotia:start-timer", {
detail: {
taskId: action.taskId ?? null,
seconds: 300,
@@ -239,8 +239,8 @@ export function startImplementationIntentions(): void {
void loadImplementationRules(true)
.then(() => checkTimeRules())
.catch(() => {});
window.addEventListener("kon:task-completed", onTaskCompleted);
window.addEventListener("kon:morning-triage-finished", onMorningTriageFinished);
window.addEventListener("magnotia:task-completed", onTaskCompleted);
window.addEventListener("magnotia:morning-triage-finished", onMorningTriageFinished);
window.addEventListener(RULES_CHANGED_EVENT, onRulesChanged);
timePollHandle = setInterval(() => {
void checkTimeRules().catch(() => {});
@@ -250,8 +250,8 @@ export function startImplementationIntentions(): void {
export function stopImplementationIntentions(): void {
if (!started) return;
started = false;
window.removeEventListener("kon:task-completed", onTaskCompleted);
window.removeEventListener("kon:morning-triage-finished", onMorningTriageFinished);
window.removeEventListener("magnotia:task-completed", onTaskCompleted);
window.removeEventListener("magnotia:morning-triage-finished", onMorningTriageFinished);
window.removeEventListener(RULES_CHANGED_EVENT, onRulesChanged);
if (timePollHandle !== null) {
clearInterval(timePollHandle);

View File

@@ -1,5 +1,5 @@
// Phase 6 Margot nudge bus. Frontend-owned, subscribes to in-app
// signals Corbie already produces, applies suppression, and fans out
// signals Magnotia already produces, applies suppression, and fans out
// to OS notification (via Rust's deliver_nudge) + optional TTS.
//
// Why frontend-only: OS-wide keyboard/window detection is fragile
@@ -191,7 +191,7 @@ async function checkPendingMorningTriage() {
triageNudgeFiredOnKey = today;
void deliver(
"A few things waiting",
"When you're ready, Corbie has your morning list. No rush.",
"When you're ready, Magnotia has your morning list. No rush.",
);
}
@@ -236,12 +236,12 @@ export function startNudgeBus(): void {
if (typeof window === "undefined") return;
started = true;
window.addEventListener("kon:start-timer", onTimerStart);
window.addEventListener("kon:focus-timer-complete", resetTimerState);
window.addEventListener("kon:focus-timer-cancelled", resetTimerState);
window.addEventListener("kon:microstep-generated", onMicroStepGenerated);
window.addEventListener("kon:step-completed", onStepOrTaskCompleted);
window.addEventListener("kon:task-completed", onStepOrTaskCompleted);
window.addEventListener("magnotia:start-timer", onTimerStart);
window.addEventListener("magnotia:focus-timer-complete", resetTimerState);
window.addEventListener("magnotia:focus-timer-cancelled", resetTimerState);
window.addEventListener("magnotia:microstep-generated", onMicroStepGenerated);
window.addEventListener("magnotia:step-completed", onStepOrTaskCompleted);
window.addEventListener("magnotia:task-completed", onStepOrTaskCompleted);
window.addEventListener("focus", onFocus);
window.addEventListener("blur", onBlur);
@@ -265,12 +265,12 @@ export function stopNudgeBus(): void {
if (!started) return;
started = false;
window.removeEventListener("kon:start-timer", onTimerStart);
window.removeEventListener("kon:focus-timer-complete", resetTimerState);
window.removeEventListener("kon:focus-timer-cancelled", resetTimerState);
window.removeEventListener("kon:microstep-generated", onMicroStepGenerated);
window.removeEventListener("kon:step-completed", onStepOrTaskCompleted);
window.removeEventListener("kon:task-completed", onStepOrTaskCompleted);
window.removeEventListener("magnotia:start-timer", onTimerStart);
window.removeEventListener("magnotia:focus-timer-complete", resetTimerState);
window.removeEventListener("magnotia:focus-timer-cancelled", resetTimerState);
window.removeEventListener("magnotia:microstep-generated", onMicroStepGenerated);
window.removeEventListener("magnotia:step-completed", onStepOrTaskCompleted);
window.removeEventListener("magnotia:task-completed", onStepOrTaskCompleted);
window.removeEventListener("focus", onFocus);
window.removeEventListener("blur", onBlur);

View File

@@ -36,10 +36,10 @@ export const page = $state<PageState>({
taskSidebarOpen: false,
});
const SETTINGS_KEY = "kon_settings";
const PROFILES_KEY = "kon_profiles";
const TASK_LISTS_KEY = "kon_task_lists";
const TEMPLATES_KEY = "kon_templates";
const SETTINGS_KEY = "magnotia_settings";
const PROFILES_KEY = "magnotia_profiles";
const TASK_LISTS_KEY = "magnotia_task_lists";
const TEMPLATES_KEY = "magnotia_templates";
const defaults: SettingsState = {
engine: "whisper",
@@ -102,8 +102,8 @@ function loadSettings(): SettingsState {
queueMicrotask(() => {
toasts.warn(
"Settings reset",
"Your saved settings couldn't be read, so Kon fell back to defaults. "
+ "Earlier Kon builds can still read your old data.",
"Your saved settings couldn't be read, so Magnotia fell back to defaults. "
+ "Earlier Magnotia builds can still read your old data.",
);
});
}
@@ -117,7 +117,7 @@ export const settings = $state<SettingsState>(loadSettings());
export function saveSettings() {
if (!canUseStorage()) return;
// Versioned envelope {version, data}. Older Kon builds that used
// Versioned envelope {version, data}. Older Magnotia builds that used
// the bare-object layout can still spread the `data` key over
// their defaults — they will just silently drop fields they don't
// know about, which is the same behaviour as today.
@@ -459,7 +459,7 @@ export async function deleteTask(id: string) {
tasks.splice(idx, 1);
broadcastTasks();
if (typeof window !== "undefined") {
window.dispatchEvent(new CustomEvent("kon:task-deleted", { detail: { id } }));
window.dispatchEvent(new CustomEvent("magnotia:task-deleted", { detail: { id } }));
}
}
} catch (err) {
@@ -477,7 +477,7 @@ export async function completeTask(id: string) {
// to this to clear micro-step-idle timers for the completed task
// and, later, to drive Phase 7 "after a task completes" rules.
if (typeof window !== "undefined") {
window.dispatchEvent(new CustomEvent("kon:task-completed", { detail: { id } }));
window.dispatchEvent(new CustomEvent("magnotia:task-completed", { detail: { id } }));
}
} catch (err) {
toasts.error("Couldn't complete task", errorMessage(err));
@@ -491,7 +491,7 @@ export async function uncompleteTask(id: string) {
await invoke("uncomplete_task_cmd", { id });
applyLocalTaskUpdate(id, { done: false, doneAt: null });
if (typeof window !== "undefined") {
window.dispatchEvent(new CustomEvent("kon:task-uncompleted", { detail: { id } }));
window.dispatchEvent(new CustomEvent("magnotia:task-uncompleted", { detail: { id } }));
}
} catch (err) {
toasts.error("Couldn't uncomplete task", errorMessage(err));
@@ -504,7 +504,7 @@ interface TaskChannelMessage {
}
const taskChannel = typeof BroadcastChannel !== "undefined"
? new BroadcastChannel("kon_task_sync")
? new BroadcastChannel("magnotia_task_sync")
: null;
if (taskChannel) {
@@ -654,7 +654,7 @@ interface TaskListChannelMessage {
}
const taskListChannel = typeof BroadcastChannel !== "undefined"
? new BroadcastChannel("kon_task_lists")
? new BroadcastChannel("magnotia_task_lists")
: null;
if (taskListChannel) {

View File

@@ -6,7 +6,7 @@ import type { AccessibilityPreferences, Preferences } from "$lib/types/app";
import { errorMessage } from "$lib/utils/errors.js";
import { toasts } from "./toasts.svelte.ts";
export const PREFERENCES_CHANGED_EVENT = "kon:preferences-changed";
export const PREFERENCES_CHANGED_EVENT = "magnotia:preferences-changed";
type FontFamilies = Record<AccessibilityPreferences["fontFamily"], string>;

View File

@@ -1,7 +1,7 @@
import type { ToastItem, ToastSeverity } from "$lib/types/app";
import { errorMessage } from "$lib/utils/errors.js";
// Minimal toast store. Roll-our-own (no svelte-french-toast etc) so Kon
// Minimal toast store. Roll-our-own (no svelte-french-toast etc) so Magnotia
// stays lean. Toasts auto-dismiss after `duration` ms unless duration is 0
// (sticky) or unless the user clicks the close button.
//

View File

@@ -99,7 +99,7 @@ export interface SettingsState {
ritualsMorningTime: string;
ritualsEvening: boolean;
/**
* Phase 5: register Corbie as a login-time autostart entry. The
* Phase 5: register Magnotia as a login-time autostart entry. The
* actual OS-level state lives in `tauri-plugin-autostart`; this
* flag mirrors it so the Settings UI can render without a round-trip
* on every mount.

View File

@@ -70,7 +70,7 @@ function toHTML(text: string, segments: Segment[]): string {
<html lang="en">
<head>
<meta charset="utf-8">
<title>Kon Transcript</title>
<title>Magnotia Transcript</title>
<style>
body { font-family: "DM Sans", system-ui, sans-serif; max-width: 700px; margin: 2rem auto; padding: 0 1rem; color: #1a1816; line-height: 1.7; }
h1 { font-family: "Instrument Serif", Georgia, serif; font-style: italic; }

View File

@@ -43,7 +43,7 @@ function timeOfDayTag(dateStr: string): string | null {
if (!dateStr) return null;
let ts = Date.parse(dateStr);
if (Number.isNaN(ts)) {
// Try DD/MM/YYYY, HH:MM:SS (UK local format used by Kon history rows).
// Try DD/MM/YYYY, HH:MM:SS (UK local format used by Magnotia history rows).
const match = String(dateStr).match(
/(\d{1,2})\/(\d{1,2})\/(\d{4})[,\s]+(\d{1,2}):(\d{2})(?::(\d{2}))?/,
);
@@ -75,7 +75,7 @@ function sourceTag(source: string): string | null {
// already shown elsewhere in the History row, so chips would duplicate
// information and add cognitive load without improving retrieval. The
// function is kept as a hook for one future AI-derived content tag
// (`topic:*`) once kon-llm wires up real llama-cpp-2 in Phase 3.
// (`topic:*`) once magnotia-llm wires up real llama-cpp-2 in Phase 3.
export function deriveAutoTags(_item: TranscriptEntry): string[] {
return [];
}

View File

@@ -42,7 +42,7 @@ export interface HotkeyParts {
trigger: string; // e.g. "R" — may be empty if we're mid-record
}
/** Tokenise a `+`-joined hotkey the way the kon-hotkey parser does,
/** Tokenise a `+`-joined hotkey the way the magnotia-hotkey parser does,
* but without demanding a fully-valid combo (we validate next). The
* last part is always the trigger key; everything before is a
* modifier. An empty/whitespace combo returns empty parts. */

View File

@@ -1,7 +1,7 @@
/**
* Forward-compatible, versioned settings migration.
*
* Historically, `localStorage["kon_settings"]` was a bare JSON object
* Historically, `localStorage["magnotia_settings"]` was a bare JSON object
* (whatever `SettingsState` looked like at write time). That shape
* tolerates new fields cleanly — spread over `defaults` — but does not
* survive:
@@ -23,7 +23,7 @@ import { parseStoredJson } from "$lib/utils/storage";
export const CURRENT_SETTINGS_VERSION = 1;
/** Envelope written to localStorage. The raw blob is always kept
* separately so a downgrade (user jumps to an older Kon build) can
* separately so a downgrade (user jumps to an older Magnotia build) can
* still read v1 data even after we've bumped to v2. */
export interface VersionedSettings<T> {
version: number;