From 5063a4f415fbef552d78f3ebd2b4ed2cb7a4aad9 Mon Sep 17 00:00:00 2001 From: Hikari Date: Tue, 24 Feb 2026 18:07:53 -0800 Subject: [PATCH] feat: display ConfigChange hook events in terminal Detects [ConfigChange Hook] lines in stderr and emits them as config-change line type with [config] prefix in purple. Closes #151 --- src-tauri/src/wsl_bridge.rs | 19 +++++++++++-------- src/lib/components/Terminal.svelte | 8 ++++++++ src/lib/components/Terminal.test.ts | 12 ++++++++++++ src/lib/tauri.ts | 6 ++++-- src/lib/types/messages.ts | 3 ++- 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src-tauri/src/wsl_bridge.rs b/src-tauri/src/wsl_bridge.rs index b074df8..083ac3c 100644 --- a/src-tauri/src/wsl_bridge.rs +++ b/src-tauri/src/wsl_bridge.rs @@ -761,18 +761,21 @@ fn handle_stderr( } } - // Worktree hook events are informational — emit with a distinct type - let is_worktree_event = line.contains("[WorktreeCreate Hook]") - || line.contains("[WorktreeRemove Hook]"); + // Hook events are informational — emit with distinct types instead of error + let line_type = if line.contains("[WorktreeCreate Hook]") + || line.contains("[WorktreeRemove Hook]") + { + "worktree" + } else if line.contains("[ConfigChange Hook]") { + "config-change" + } else { + "error" + }; let _ = app.emit( "claude:output", OutputEvent { - line_type: if is_worktree_event { - "worktree".to_string() - } else { - "error".to_string() - }, + line_type: line_type.to_string(), content: line, tool_name: None, conversation_id: conversation_id.clone(), diff --git a/src/lib/components/Terminal.svelte b/src/lib/components/Terminal.svelte index 9d476bb..1d1f665 100644 --- a/src/lib/components/Terminal.svelte +++ b/src/lib/components/Terminal.svelte @@ -100,6 +100,8 @@ return "terminal-compact-prompt"; case "worktree": return "terminal-worktree"; + case "config-change": + return "terminal-config-change"; default: return "terminal-default"; } @@ -121,6 +123,8 @@ return "[rate-limit]"; case "worktree": return "[worktree]"; + case "config-change": + return "[config]"; default: return ""; } @@ -394,6 +398,10 @@ color: var(--terminal-worktree, #34d399); } + .terminal-config-change { + color: var(--terminal-config-change, #a78bfa); + } + .compact-action-btn { display: inline-flex; align-items: center; diff --git a/src/lib/components/Terminal.test.ts b/src/lib/components/Terminal.test.ts index 9e3023b..4d6344d 100644 --- a/src/lib/components/Terminal.test.ts +++ b/src/lib/components/Terminal.test.ts @@ -42,6 +42,8 @@ function getLineClass(type: string): string { return "terminal-compact-prompt"; case "worktree": return "terminal-worktree"; + case "config-change": + return "terminal-config-change"; default: return "terminal-default"; } @@ -63,6 +65,8 @@ function getLinePrefix(type: string): string { return "[rate-limit]"; case "worktree": return "[worktree]"; + case "config-change": + return "[config]"; default: return ""; } @@ -124,6 +128,10 @@ describe("getLineClass", () => { expect(getLineClass("worktree")).toBe("terminal-worktree"); }); + it("returns terminal-config-change for config-change lines", () => { + expect(getLineClass("config-change")).toBe("terminal-config-change"); + }); + it("returns terminal-default for unknown line types", () => { expect(getLineClass("unknown")).toBe("terminal-default"); expect(getLineClass("")).toBe("terminal-default"); @@ -164,6 +172,10 @@ describe("getLinePrefix", () => { expect(getLinePrefix("worktree")).toBe("[worktree]"); }); + it("returns [config] for config-change lines", () => { + expect(getLinePrefix("config-change")).toBe("[config]"); + }); + it("returns empty string for thinking lines (no prefix)", () => { expect(getLinePrefix("thinking")).toBe(""); }); diff --git a/src/lib/tauri.ts b/src/lib/tauri.ts index 7c1166d..072e8f8 100644 --- a/src/lib/tauri.ts +++ b/src/lib/tauri.ts @@ -332,7 +332,8 @@ export async function initializeTauriListeners() { | "thinking" | "rate-limit" | "compact-prompt" - | "worktree", + | "worktree" + | "config-change", content, tool_name || undefined, costData, @@ -350,7 +351,8 @@ export async function initializeTauriListeners() { | "thinking" | "rate-limit" | "compact-prompt" - | "worktree", + | "worktree" + | "config-change", content, tool_name || undefined, costData, diff --git a/src/lib/types/messages.ts b/src/lib/types/messages.ts index 5531375..15ca219 100644 --- a/src/lib/types/messages.ts +++ b/src/lib/types/messages.ts @@ -9,7 +9,8 @@ export interface TerminalLine { | "thinking" | "rate-limit" | "compact-prompt" - | "worktree"; + | "worktree" + | "config-change"; content: string; timestamp: Date; toolName?: string;