generated from nhcarrigan/template
feat: greet on connect
This commit is contained in:
@@ -40,6 +40,16 @@ pub struct HikariConfig {
|
|||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub theme: Theme,
|
pub theme: Theme,
|
||||||
|
|
||||||
|
#[serde(default = "default_greeting_enabled")]
|
||||||
|
pub greeting_enabled: bool,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub greeting_custom_prompt: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_greeting_enabled() -> bool {
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
|
||||||
@@ -63,6 +73,8 @@ mod tests {
|
|||||||
assert!(config.mcp_servers_json.is_none());
|
assert!(config.mcp_servers_json.is_none());
|
||||||
assert!(config.auto_granted_tools.is_empty());
|
assert!(config.auto_granted_tools.is_empty());
|
||||||
assert_eq!(config.theme, Theme::Dark);
|
assert_eq!(config.theme, Theme::Dark);
|
||||||
|
assert!(!config.greeting_enabled);
|
||||||
|
assert!(config.greeting_custom_prompt.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -74,6 +86,8 @@ mod tests {
|
|||||||
mcp_servers_json: None,
|
mcp_servers_json: None,
|
||||||
auto_granted_tools: vec!["Read".to_string(), "Glob".to_string()],
|
auto_granted_tools: vec!["Read".to_string(), "Glob".to_string()],
|
||||||
theme: Theme::Light,
|
theme: Theme::Light,
|
||||||
|
greeting_enabled: true,
|
||||||
|
greeting_custom_prompt: Some("Hello!".to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let json = serde_json::to_string(&config).unwrap();
|
let json = serde_json::to_string(&config).unwrap();
|
||||||
@@ -83,6 +97,8 @@ mod tests {
|
|||||||
assert_eq!(deserialized.custom_instructions, config.custom_instructions);
|
assert_eq!(deserialized.custom_instructions, config.custom_instructions);
|
||||||
assert_eq!(deserialized.auto_granted_tools, config.auto_granted_tools);
|
assert_eq!(deserialized.auto_granted_tools, config.auto_granted_tools);
|
||||||
assert_eq!(deserialized.theme, Theme::Light);
|
assert_eq!(deserialized.theme, Theme::Light);
|
||||||
|
assert!(deserialized.greeting_enabled);
|
||||||
|
assert_eq!(deserialized.greeting_custom_prompt, Some("Hello!".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
mcp_servers_json: null,
|
mcp_servers_json: null,
|
||||||
auto_granted_tools: [],
|
auto_granted_tools: [],
|
||||||
theme: "dark",
|
theme: "dark",
|
||||||
|
greeting_enabled: true,
|
||||||
|
greeting_custom_prompt: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
let isOpen = $state(false);
|
let isOpen = $state(false);
|
||||||
@@ -220,6 +222,44 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Greeting Section -->
|
||||||
|
<section class="mb-6">
|
||||||
|
<h3 class="text-sm font-medium text-[var(--accent-primary)] uppercase tracking-wider mb-3">
|
||||||
|
Greeting
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<!-- Enable/Disable Toggle -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="flex items-center gap-3 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
bind:checked={config.greeting_enabled}
|
||||||
|
class="w-4 h-4 rounded border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--accent-primary)] focus:ring-[var(--accent-primary)]"
|
||||||
|
/>
|
||||||
|
<span class="text-sm text-gray-300">Send greeting on connect</span>
|
||||||
|
</label>
|
||||||
|
<p class="text-xs text-gray-500 mt-1 ml-7">
|
||||||
|
Automatically greet you when a session starts with time-based messages
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Custom Greeting Prompt -->
|
||||||
|
{#if config.greeting_enabled}
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="greeting-prompt" class="block text-sm text-gray-400 mb-1">
|
||||||
|
Custom Greeting Prompt <span class="text-gray-600">(optional)</span>
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
id="greeting-prompt"
|
||||||
|
bind:value={config.greeting_custom_prompt}
|
||||||
|
rows="3"
|
||||||
|
placeholder="Leave empty for time-based greetings, or customize how you'd like to be greeted..."
|
||||||
|
class="w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border-color)] rounded-lg text-[var(--text-primary)] focus:outline-none focus:border-[var(--accent-primary)] resize-none"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- MCP Servers Section -->
|
<!-- MCP Servers Section -->
|
||||||
<section class="mb-6">
|
<section class="mb-6">
|
||||||
<h3 class="text-sm font-medium text-[var(--accent-primary)] uppercase tracking-wider mb-3">
|
<h3 class="text-sm font-medium text-[var(--accent-primary)] uppercase tracking-wider mb-3">
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ export interface HikariConfig {
|
|||||||
mcp_servers_json: string | null;
|
mcp_servers_json: string | null;
|
||||||
auto_granted_tools: string[];
|
auto_granted_tools: string[];
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
greeting_enabled: boolean;
|
||||||
|
greeting_custom_prompt: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultConfig: HikariConfig = {
|
const defaultConfig: HikariConfig = {
|
||||||
@@ -19,6 +21,8 @@ const defaultConfig: HikariConfig = {
|
|||||||
mcp_servers_json: null,
|
mcp_servers_json: null,
|
||||||
auto_granted_tools: [],
|
auto_granted_tools: [],
|
||||||
theme: "dark",
|
theme: "dark",
|
||||||
|
greeting_enabled: true,
|
||||||
|
greeting_custom_prompt: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
function createConfigStore() {
|
function createConfigStore() {
|
||||||
|
|||||||
+35
-1
@@ -1,6 +1,8 @@
|
|||||||
import { listen } from "@tauri-apps/api/event";
|
import { listen } from "@tauri-apps/api/event";
|
||||||
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { claudeStore } from "$lib/stores/claude";
|
import { claudeStore } from "$lib/stores/claude";
|
||||||
import { characterState } from "$lib/stores/character";
|
import { characterState } from "$lib/stores/character";
|
||||||
|
import { configStore } from "$lib/stores/config";
|
||||||
import type { ConnectionStatus, PermissionPromptEvent } from "$lib/types/messages";
|
import type { ConnectionStatus, PermissionPromptEvent } from "$lib/types/messages";
|
||||||
import type { CharacterState } from "$lib/types/states";
|
import type { CharacterState } from "$lib/types/states";
|
||||||
|
|
||||||
@@ -9,6 +11,36 @@ interface StateChangePayload {
|
|||||||
tool_name: string | null;
|
tool_name: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateTimeBasedGreeting(): string {
|
||||||
|
const hour = new Date().getHours();
|
||||||
|
|
||||||
|
if (hour >= 5 && hour < 12) {
|
||||||
|
return "Good morning! How can I help you today?";
|
||||||
|
} else if (hour >= 12 && hour < 17) {
|
||||||
|
return "Good afternoon! What are we working on?";
|
||||||
|
} else if (hour >= 17 && hour < 21) {
|
||||||
|
return "Good evening! Ready to get some work done?";
|
||||||
|
} else {
|
||||||
|
return "Working late? I'm here to help!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendGreeting() {
|
||||||
|
const config = configStore.getConfig();
|
||||||
|
|
||||||
|
if (!config.greeting_enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const greetingPrompt = config.greeting_custom_prompt?.trim() || generateTimeBasedGreeting();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await invoke("send_prompt", { message: greetingPrompt });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to send greeting:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface OutputPayload {
|
interface OutputPayload {
|
||||||
line_type: string;
|
line_type: string;
|
||||||
content: string;
|
content: string;
|
||||||
@@ -69,9 +101,11 @@ export async function initializeTauriListeners() {
|
|||||||
// no-op
|
// no-op
|
||||||
});
|
});
|
||||||
|
|
||||||
await listen<string>("claude:session", (event) => {
|
await listen<string>("claude:session", async (event) => {
|
||||||
claudeStore.setSessionId(event.payload);
|
claudeStore.setSessionId(event.payload);
|
||||||
claudeStore.addLine("system", `Session: ${event.payload.substring(0, 8)}...`);
|
claudeStore.addLine("system", `Session: ${event.payload.substring(0, 8)}...`);
|
||||||
|
|
||||||
|
await sendGreeting();
|
||||||
});
|
});
|
||||||
|
|
||||||
await listen<string>("claude:cwd", (event) => {
|
await listen<string>("claude:cwd", (event) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user