generated from nhcarrigan/template
feat: batch of fixes and features (#56)
## Summary This PR includes a batch of bug fixes and new features: ### Bug Fixes - **Links in chat history now open in default browser** instead of navigating within the app - Closes #54 - **Allow spaces in tab names** - space key no longer acts like enter when renaming tabs - Closes #52 ### New Features - **`/cd` command** - Change the working directory of an active tab with context preservation - Closes #55 - **`/search` command** - Search and highlight matches within the conversation - Closes #32 ## Test Plan - [ ] Click a link in chat history and verify it opens in the default browser - [ ] Rename a tab and verify spaces can be typed - [ ] Use `/cd <path>` and verify the directory changes while preserving conversation context - [ ] Use `/search <query>` and verify matches are highlighted in yellow - [ ] Use `/search` with no args to clear the search highlighting ✨ This PR was created with help from Hikari~ 🌸 Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com> Reviewed-on: #56 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
This commit was merged in pull request #56.
This commit is contained in:
@@ -3,6 +3,7 @@ import { invoke } from "@tauri-apps/api/core";
|
||||
import { claudeStore } from "$lib/stores/claude";
|
||||
import { characterState } from "$lib/stores/character";
|
||||
import { setSkipNextGreeting } from "$lib/tauri";
|
||||
import { searchState } from "$lib/stores/search";
|
||||
|
||||
export interface SlashCommand {
|
||||
name: string;
|
||||
@@ -11,6 +12,71 @@ export interface SlashCommand {
|
||||
execute: (args: string) => Promise<void> | void;
|
||||
}
|
||||
|
||||
async function changeDirectory(path: string): Promise<void> {
|
||||
const conversationId = get(claudeStore.activeConversationId);
|
||||
if (!conversationId) {
|
||||
claudeStore.addLine("error", "No active conversation");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!path.trim()) {
|
||||
const currentDir = get(claudeStore.currentWorkingDirectory);
|
||||
claudeStore.addLine("system", `Current directory: ${currentDir}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
characterState.setState("thinking");
|
||||
claudeStore.addLine("system", `Changing directory to: ${path}`);
|
||||
|
||||
const currentDir = get(claudeStore.currentWorkingDirectory);
|
||||
const validatedPath = await invoke<string>("validate_directory", { path, currentDir });
|
||||
|
||||
// Capture conversation history before disconnecting
|
||||
const conversationHistory = claudeStore.getConversationHistory();
|
||||
|
||||
await invoke("stop_claude", { conversationId });
|
||||
|
||||
// Wait for clean shutdown
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
|
||||
claudeStore.setWorkingDirectory(validatedPath);
|
||||
|
||||
setSkipNextGreeting(true);
|
||||
|
||||
await invoke("start_claude", {
|
||||
conversationId,
|
||||
options: {
|
||||
working_dir: validatedPath,
|
||||
},
|
||||
});
|
||||
|
||||
// Wait for connection to establish
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
|
||||
// Restore context if there was conversation history
|
||||
if (conversationHistory) {
|
||||
const contextMessage = `[CONTEXT RESTORATION]
|
||||
I just changed the working directory from ${currentDir} to ${validatedPath}. Here's our conversation so far:
|
||||
|
||||
${conversationHistory}
|
||||
|
||||
Please continue where we left off. You are now operating in the new directory.`;
|
||||
|
||||
await invoke("send_prompt", {
|
||||
conversationId,
|
||||
message: contextMessage,
|
||||
});
|
||||
}
|
||||
|
||||
claudeStore.addLine("system", `Changed directory to: ${validatedPath}`);
|
||||
characterState.setState("idle");
|
||||
} catch (error) {
|
||||
claudeStore.addLine("error", `Failed to change directory: ${error}`);
|
||||
characterState.setTemporaryState("error", 3000);
|
||||
}
|
||||
}
|
||||
|
||||
async function startNewConversation(): Promise<void> {
|
||||
const conversationId = get(claudeStore.activeConversationId);
|
||||
if (!conversationId) {
|
||||
@@ -48,6 +114,12 @@ async function startNewConversation(): Promise<void> {
|
||||
}
|
||||
|
||||
export const slashCommands: SlashCommand[] = [
|
||||
{
|
||||
name: "cd",
|
||||
description: "Change the working directory",
|
||||
usage: "/cd <path>",
|
||||
execute: changeDirectory,
|
||||
},
|
||||
{
|
||||
name: "clear",
|
||||
description: "Clear the terminal display (keeps conversation context)",
|
||||
@@ -74,6 +146,20 @@ export const slashCommands: SlashCommand[] = [
|
||||
claudeStore.addLine("system", `Available commands:\n${helpText}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "search",
|
||||
description: "Search within the conversation (use /search to clear)",
|
||||
usage: "/search [query]",
|
||||
execute: (args: string) => {
|
||||
if (!args.trim()) {
|
||||
searchState.clear();
|
||||
claudeStore.addLine("system", "Search cleared");
|
||||
return;
|
||||
}
|
||||
searchState.setQuery(args.trim());
|
||||
claudeStore.addLine("system", `Searching for: "${args.trim()}"`);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "summarise",
|
||||
description: "Get a summary of the entire conversation",
|
||||
|
||||
Reference in New Issue
Block a user