generated from nhcarrigan/template
feat: add ability to run multiple agents via tabbed views (#47)
### Explanation _No response_ ### Issue Closes #30 Closes #41 ### Attestations - [ ] I have read and agree to the [Code of Conduct](https://docs.nhcarrigan.com/community/coc/) - [ ] I have read and agree to the [Community Guidelines](https://docs.nhcarrigan.com/community/guide/). - [ ] My contribution complies with the [Contributor Covenant](https://docs.nhcarrigan.com/dev/covenant/). ### Dependencies - [ ] I have pinned the dependencies to a specific patch version. ### Style - [ ] I have run the linter and resolved any errors. - [ ] My pull request uses an appropriate title, matching the conventional commit standards. - [ ] My scope of feat/fix/chore/etc. correctly matches the nature of changes in my pull request. ### Tests - [ ] My contribution adds new code, and I have added tests to cover it. - [ ] My contribution modifies existing code, and I have updated the tests to reflect these changes. - [ ] All new and existing tests pass locally with my changes. - [ ] Code coverage remains at or above the configured threshold. ### Documentation _No response_ ### Versioning _No response_ Reviewed-on: #47 Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com> Co-committed-by: Naomi Carrigan <commits@nhcarrigan.com>
This commit was merged in pull request #47.
This commit is contained in:
+74
-135
@@ -1,147 +1,86 @@
|
||||
import { writable, derived } from "svelte/store";
|
||||
import type { ConnectionStatus, PermissionRequest } from "$lib/types/messages";
|
||||
import { derived } from "svelte/store";
|
||||
import { conversationsStore } from "./conversations";
|
||||
import type { TerminalLine } from "$lib/types/messages";
|
||||
import { characterState } from "$lib/stores/character";
|
||||
import {
|
||||
setShouldRestoreHistory,
|
||||
setSavedHistory,
|
||||
getShouldRestoreHistory,
|
||||
getSavedHistory,
|
||||
clearHistoryRestore,
|
||||
} from "./historyRestore";
|
||||
|
||||
export interface TerminalLine {
|
||||
id: string;
|
||||
type: "user" | "assistant" | "system" | "tool" | "error";
|
||||
content: string;
|
||||
timestamp: Date;
|
||||
toolName?: string;
|
||||
}
|
||||
// Re-export TerminalLine type for backwards compatibility
|
||||
export type { TerminalLine };
|
||||
|
||||
function createClaudeStore() {
|
||||
const connectionStatus = writable<ConnectionStatus>("disconnected");
|
||||
const sessionId = writable<string | null>(null);
|
||||
const currentWorkingDirectory = writable<string>("");
|
||||
const terminalLines = writable<TerminalLine[]>([]);
|
||||
const pendingPermission = writable<PermissionRequest | null>(null);
|
||||
const isProcessing = writable<boolean>(false);
|
||||
const grantedTools = writable<Set<string>>(new Set());
|
||||
const pendingRetryMessage = writable<string | null>(null);
|
||||
const shouldRestoreHistory = writable<boolean>(false);
|
||||
const savedConversationHistory = writable<string | null>(null);
|
||||
// Re-export from conversations store for backwards compatibility
|
||||
export const claudeStore = {
|
||||
// Existing subscriptions
|
||||
connectionStatus: conversationsStore.connectionStatus,
|
||||
sessionId: conversationsStore.sessionId,
|
||||
currentWorkingDirectory: conversationsStore.currentWorkingDirectory,
|
||||
terminalLines: conversationsStore.terminalLines,
|
||||
pendingPermission: conversationsStore.pendingPermission,
|
||||
isProcessing: conversationsStore.isProcessing,
|
||||
grantedTools: conversationsStore.grantedTools,
|
||||
pendingRetryMessage: conversationsStore.pendingRetryMessage,
|
||||
|
||||
let lineIdCounter = 0;
|
||||
// New conversation-aware subscriptions
|
||||
conversations: conversationsStore.conversations,
|
||||
activeConversationId: conversationsStore.activeConversationId,
|
||||
activeConversation: conversationsStore.activeConversation,
|
||||
|
||||
function generateLineId(): string {
|
||||
return `line-${Date.now()}-${lineIdCounter++}`;
|
||||
}
|
||||
// Methods
|
||||
setConnectionStatus: conversationsStore.setConnectionStatus,
|
||||
setConnectionStatusForConversation: conversationsStore.setConnectionStatusForConversation,
|
||||
setCharacterStateForConversation: conversationsStore.setCharacterStateForConversation,
|
||||
setSessionId: conversationsStore.setSessionId,
|
||||
setSessionIdForConversation: conversationsStore.setSessionIdForConversation,
|
||||
setWorkingDirectory: conversationsStore.setWorkingDirectory,
|
||||
setWorkingDirectoryForConversation: conversationsStore.setWorkingDirectoryForConversation,
|
||||
setProcessing: conversationsStore.setProcessing,
|
||||
addLine: conversationsStore.addLine,
|
||||
addLineToConversation: conversationsStore.addLineToConversation,
|
||||
updateLine: conversationsStore.updateLine,
|
||||
appendToLine: conversationsStore.appendToLine,
|
||||
clearTerminal: conversationsStore.clearTerminal,
|
||||
getConversationHistory: conversationsStore.getConversationHistory,
|
||||
requestPermission: conversationsStore.requestPermission,
|
||||
clearPermission: conversationsStore.clearPermission,
|
||||
grantTool: conversationsStore.grantTool,
|
||||
revokeAllTools: conversationsStore.revokeAllTools,
|
||||
isToolGranted: conversationsStore.isToolGranted,
|
||||
setPendingRetryMessage: conversationsStore.setPendingRetryMessage,
|
||||
|
||||
return {
|
||||
connectionStatus: { subscribe: connectionStatus.subscribe },
|
||||
sessionId: { subscribe: sessionId.subscribe },
|
||||
currentWorkingDirectory: { subscribe: currentWorkingDirectory.subscribe },
|
||||
terminalLines: { subscribe: terminalLines.subscribe },
|
||||
pendingPermission: { subscribe: pendingPermission.subscribe },
|
||||
isProcessing: { subscribe: isProcessing.subscribe },
|
||||
grantedTools: { subscribe: grantedTools.subscribe },
|
||||
pendingRetryMessage: { subscribe: pendingRetryMessage.subscribe },
|
||||
shouldRestoreHistory: { subscribe: shouldRestoreHistory.subscribe },
|
||||
savedConversationHistory: { subscribe: savedConversationHistory.subscribe },
|
||||
// Conversation management
|
||||
createConversation: conversationsStore.createConversation,
|
||||
deleteConversation: conversationsStore.deleteConversation,
|
||||
switchConversation: conversationsStore.switchConversation,
|
||||
renameConversation: conversationsStore.renameConversation,
|
||||
|
||||
setConnectionStatus: (status: ConnectionStatus) => connectionStatus.set(status),
|
||||
setSessionId: (id: string | null) => sessionId.set(id),
|
||||
setWorkingDirectory: (dir: string) => currentWorkingDirectory.set(dir),
|
||||
setProcessing: (processing: boolean) => isProcessing.set(processing),
|
||||
getGrantedTools: (): string[] => {
|
||||
let tools: string[] = [];
|
||||
conversationsStore.grantedTools.subscribe((t) => (tools = Array.from(t)))();
|
||||
return tools;
|
||||
},
|
||||
|
||||
addLine: (type: TerminalLine["type"], content: string, toolName?: string) => {
|
||||
const line: TerminalLine = {
|
||||
id: generateLineId(),
|
||||
type,
|
||||
content,
|
||||
timestamp: new Date(),
|
||||
toolName,
|
||||
};
|
||||
terminalLines.update((lines) => [...lines, line]);
|
||||
return line.id;
|
||||
},
|
||||
// History restoration methods from main branch
|
||||
setShouldRestoreHistory: setShouldRestoreHistory,
|
||||
setSavedConversationHistory: setSavedHistory,
|
||||
getShouldRestoreHistory: getShouldRestoreHistory,
|
||||
getSavedConversationHistory: getSavedHistory,
|
||||
|
||||
updateLine: (id: string, content: string) => {
|
||||
terminalLines.update((lines) =>
|
||||
lines.map((line) => (line.id === id ? { ...line, content } : line))
|
||||
);
|
||||
},
|
||||
|
||||
appendToLine: (id: string, additionalContent: string) => {
|
||||
terminalLines.update((lines) =>
|
||||
lines.map((line) =>
|
||||
line.id === id ? { ...line, content: line.content + additionalContent } : line
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
clearTerminal: () => terminalLines.set([]),
|
||||
|
||||
getConversationHistory: (): string => {
|
||||
let lines: TerminalLine[] = [];
|
||||
terminalLines.subscribe((l) => (lines = l))();
|
||||
|
||||
// Filter to just user and assistant messages, skip system/tool noise
|
||||
const relevantLines = lines.filter(
|
||||
(line) => line.type === "user" || line.type === "assistant"
|
||||
);
|
||||
|
||||
if (relevantLines.length === 0) return "";
|
||||
|
||||
return relevantLines
|
||||
.map((line) => {
|
||||
const role = line.type === "user" ? "User" : "Assistant";
|
||||
return `${role}: ${line.content}`;
|
||||
})
|
||||
.join("\n\n");
|
||||
},
|
||||
|
||||
requestPermission: (request: PermissionRequest) => pendingPermission.set(request),
|
||||
clearPermission: () => pendingPermission.set(null),
|
||||
|
||||
grantTool: (toolName: string) => {
|
||||
grantedTools.update((tools) => {
|
||||
const newTools = new Set(tools);
|
||||
newTools.add(toolName);
|
||||
return newTools;
|
||||
});
|
||||
},
|
||||
|
||||
getGrantedTools: (): string[] => {
|
||||
let tools: string[] = [];
|
||||
grantedTools.subscribe((t) => (tools = Array.from(t)))();
|
||||
return tools;
|
||||
},
|
||||
|
||||
setPendingRetryMessage: (message: string | null) => pendingRetryMessage.set(message),
|
||||
|
||||
setShouldRestoreHistory: (should: boolean) => shouldRestoreHistory.set(should),
|
||||
setSavedConversationHistory: (history: string | null) => savedConversationHistory.set(history),
|
||||
|
||||
getShouldRestoreHistory: (): boolean => {
|
||||
let should = false;
|
||||
shouldRestoreHistory.subscribe((s) => (should = s))();
|
||||
return should;
|
||||
},
|
||||
|
||||
getSavedConversationHistory: (): string | null => {
|
||||
let history: string | null = null;
|
||||
savedConversationHistory.subscribe((h) => (history = h))();
|
||||
return history;
|
||||
},
|
||||
|
||||
reset: () => {
|
||||
connectionStatus.set("disconnected");
|
||||
sessionId.set(null);
|
||||
currentWorkingDirectory.set("");
|
||||
terminalLines.set([]);
|
||||
pendingPermission.set(null);
|
||||
isProcessing.set(false);
|
||||
grantedTools.set(new Set());
|
||||
pendingRetryMessage.set(null);
|
||||
shouldRestoreHistory.set(false);
|
||||
savedConversationHistory.set(null);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const claudeStore = createClaudeStore();
|
||||
reset: () => {
|
||||
// Reset only the active conversation
|
||||
conversationsStore.clearTerminal();
|
||||
conversationsStore.setSessionId(null);
|
||||
conversationsStore.setWorkingDirectory("");
|
||||
conversationsStore.setProcessing(false);
|
||||
conversationsStore.revokeAllTools();
|
||||
// Also clear history restoration
|
||||
clearHistoryRestore();
|
||||
},
|
||||
};
|
||||
|
||||
export const hasPermissionPending = derived(
|
||||
claudeStore.pendingPermission,
|
||||
|
||||
Reference in New Issue
Block a user