diff --git a/src-tauri/src/config.rs b/src-tauri/src/config.rs
index 69f3e7a..5bf59fd 100644
--- a/src-tauri/src/config.rs
+++ b/src-tauri/src/config.rs
@@ -73,6 +73,12 @@ pub struct HikariConfig {
#[serde(default)]
pub minimize_to_tray: bool,
+
+ #[serde(default)]
+ pub streamer_mode: bool,
+
+ #[serde(default)]
+ pub streamer_hide_paths: bool,
}
impl Default for HikariConfig {
@@ -93,6 +99,8 @@ impl Default for HikariConfig {
character_panel_width: None,
font_size: 14,
minimize_to_tray: false,
+ streamer_mode: false,
+ streamer_hide_paths: false,
}
}
}
@@ -147,6 +155,8 @@ mod tests {
assert!(config.character_panel_width.is_none());
assert_eq!(config.font_size, 14);
assert!(!config.minimize_to_tray);
+ assert!(!config.streamer_mode);
+ assert!(!config.streamer_hide_paths);
}
#[test]
diff --git a/src/lib/components/ConfigSidebar.svelte b/src/lib/components/ConfigSidebar.svelte
index 335bad9..6015b62 100644
--- a/src/lib/components/ConfigSidebar.svelte
+++ b/src/lib/components/ConfigSidebar.svelte
@@ -27,6 +27,8 @@
update_checks_enabled: true,
character_panel_width: null,
font_size: 14,
+ streamer_mode: false,
+ streamer_hide_paths: false,
});
let isOpen = $state(false);
@@ -187,47 +189,60 @@
@@ -519,6 +534,45 @@
+
+
+
+ Privacy / Streamer Mode
+
+
+
+
+
+
+ Hide sensitive information like API keys when streaming (Ctrl+Shift+S to toggle)
+
+
+
+
+ {#if config.streamer_mode}
+
+
+
+ Mask directory paths (e.g., /home/user → /home/****)
+
+
+ {/if}
+
+
diff --git a/src/lib/components/InputBar.svelte b/src/lib/components/InputBar.svelte
index b8f82cc..d798985 100644
--- a/src/lib/components/InputBar.svelte
+++ b/src/lib/components/InputBar.svelte
@@ -25,6 +25,7 @@
isSlashCommand,
type SlashCommand,
} from "$lib/commands/slashCommands";
+ import { configStore, isStreamerMode } from "$lib/stores/config";
import AttachmentPreview from "$lib/components/AttachmentPreview.svelte";
import SnippetLibraryPanel from "$lib/components/SnippetLibraryPanel.svelte";
import QuickActionsPanel from "$lib/components/QuickActionsPanel.svelte";
@@ -46,6 +47,11 @@
let showSnippetLibrary = $state(false);
let showQuickActions = $state(false);
let showClipboardHistory = $state(false);
+ let streamerModeActive = $state(false);
+
+ isStreamerMode.subscribe((value) => {
+ streamerModeActive = value;
+ });
// Input history state
let inputHistory = $state([]);
@@ -765,6 +771,34 @@ User: ${formattedMessage}`;
+ {#if streamerModeActive}
+
+ {/if}
{/each}
diff --git a/src/lib/stores/config.ts b/src/lib/stores/config.ts
index 86b069c..afdecd0 100644
--- a/src/lib/stores/config.ts
+++ b/src/lib/stores/config.ts
@@ -19,6 +19,8 @@ export interface HikariConfig {
update_checks_enabled: boolean;
character_panel_width: number | null;
font_size: number;
+ streamer_mode: boolean;
+ streamer_hide_paths: boolean;
}
const defaultConfig: HikariConfig = {
@@ -37,6 +39,8 @@ const defaultConfig: HikariConfig = {
update_checks_enabled: true,
character_panel_width: null,
font_size: 14,
+ streamer_mode: false,
+ streamer_hide_paths: false,
};
function createConfigStore() {
@@ -145,6 +149,12 @@ function createConfigStore() {
config.subscribe((c) => (currentConfig = c))();
return currentConfig;
},
+
+ toggleStreamerMode: async () => {
+ let currentConfig: HikariConfig = defaultConfig;
+ config.subscribe((c) => (currentConfig = c))();
+ await updateConfig({ streamer_mode: !currentConfig.streamer_mode });
+ },
};
}
@@ -174,3 +184,25 @@ export { MIN_FONT_SIZE, MAX_FONT_SIZE, DEFAULT_FONT_SIZE };
export const configStore = createConfigStore();
export const isDarkTheme = derived(configStore.config, ($config) => $config.theme === "dark");
+
+export const isStreamerMode = derived(configStore.config, ($config) => $config.streamer_mode);
+export const shouldHidePaths = derived(
+ configStore.config,
+ ($config) => $config.streamer_mode && $config.streamer_hide_paths
+);
+
+/**
+ * Masks file paths in text when streamer mode with hide paths is enabled.
+ * Replaces username portion of paths with asterisks.
+ */
+export function maskPaths(text: string, hidePaths: boolean): string {
+ if (!hidePaths) return text;
+
+ // Match Unix paths like /home/username/... or /Users/username/...
+ // and Windows paths like C:\Users\username\...
+ return text
+ .replace(/\/home\/([^\/\s]+)/g, "/home/****")
+ .replace(/\/Users\/([^\/\s]+)/g, "/Users/****")
+ .replace(/C:\\Users\\([^\\\s]+)/gi, "C:\\Users\\****")
+ .replace(/~\//g, "****/");
+}
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 3c22695..169c5a1 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -149,6 +149,13 @@
configStore.resetFontSize();
return;
}
+
+ // Ctrl+Shift+S - Toggle streamer mode
+ if (event.ctrlKey && event.shiftKey && event.key === "S") {
+ event.preventDefault();
+ configStore.toggleStreamerMode();
+ return;
+ }
}
async function handleInterrupt() {