Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
435 changes: 247 additions & 188 deletions package-lock.json

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"framer-motion": "^12.23.26",
"immer": "^11.0.1",
"lexical": "^0.39.0",
"lucide-react": "^0.561.0",
"lucide-react": "^0.562.0",
"next-themes": "^0.4.6",
"react": "^19.2.3",
"react-dom": "^19.2.3",
Expand All @@ -89,17 +89,17 @@
"tailwindcss": "^4.0.0",
"tailwindcss-animate": "^1.0.7",
"tw-animate-css": "^1.4.0",
"zod": "^3.23.8",
"zod": "^4.2.1",
"zustand": "^5.0.0"
},
"devDependencies": {
"@eslint/js": "^9.39.2",
"@tauri-apps/cli": "^2.0.0",
"@types/node": "^25.0.2",
"@types/node": "^25.0.3",
"@types/react": "^19.0.2",
"@types/react-dom": "^19.0.2",
"@typescript-eslint/eslint-plugin": "^8.17.0",
"@typescript-eslint/parser": "^8.17.0",
"@typescript-eslint/eslint-plugin": "^8.50.0",
"@typescript-eslint/parser": "^8.50.0",
"@vitejs/plugin-react": "^5.1.2",
"eslint": "^9.39.2",
"eslint-plugin-import-x": "^4.16.1",
Expand All @@ -109,7 +109,7 @@
"lint-staged": "^16.2.7",
"prettier": "^3.7.4",
"typescript": "^5.7.2",
"typescript-eslint": "^8.49.0",
"vite": "^7.2.7"
"typescript-eslint": "^8.50.0",
"vite": "^7.3.0"
}
}
28 changes: 16 additions & 12 deletions src/hooks/use-tauri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export function useTauri(options: UseTauriOptions = {}): UseTauriReturn {
if (!result.success) {
if (debug) {
console.warn('[Snowflake] Invalid message:', event.data);
console.warn('[Snowflake] Errors:', result.error.format());
console.warn('[Snowflake] Errors:', result.error.issues);
}
return;
}
Expand Down Expand Up @@ -120,7 +120,7 @@ export function useTauri(options: UseTauriOptions = {}): UseTauriReturn {
(message: WebviewMessage): void => {
const result = WebviewMessageSchema.safeParse(message);
if (!result.success) {
console.error('[Snowflake] Invalid outgoing message:', result.error.format());
console.error('[Snowflake] Invalid outgoing message:', result.error.issues);
return;
}

Expand Down Expand Up @@ -308,8 +308,18 @@ function handleMockMessage(message: WebviewMessage): void {
children: [
{ name: 'src', path: `${mockPath}/src`, isDirectory: true, isFile: false },
{ name: 'tests', path: `${mockPath}/tests`, isDirectory: true, isFile: false },
{ name: 'package.json', path: `${mockPath}/package.json`, isDirectory: false, isFile: true },
{ name: 'README.md', path: `${mockPath}/README.md`, isDirectory: false, isFile: true },
{
name: 'package.json',
path: `${mockPath}/package.json`,
isDirectory: false,
isFile: true,
},
{
name: 'README.md',
path: `${mockPath}/README.md`,
isDirectory: false,
isFile: true,
},
],
},
'*'
Expand Down Expand Up @@ -401,19 +411,13 @@ function handleMockMessage(message: WebviewMessage): void {

export interface AgentStreamCallbacks {
onChunk: (content: string, messageId: string) => void;
onComplete: (
messageId: string,
usage?: { input_tokens: number; output_tokens: number }
) => void;
onComplete: (messageId: string, usage?: { input_tokens: number; output_tokens: number }) => void;
onError: (error: string, messageId: string) => void;
onToolStart?: (toolName: string, messageId: string) => void;
onToolEnd?: (toolName: string, success: boolean, messageId: string) => void;
}

export function useAgentStream(
sessionId: string,
callbacks: AgentStreamCallbacks
): void {
export function useAgentStream(sessionId: string, callbacks: AgentStreamCallbacks): void {
const { onChunk, onComplete, onError, onToolStart, onToolEnd } = callbacks;

const handleMessage = useCallback(
Expand Down
14 changes: 6 additions & 8 deletions src/types/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export enum ToolCallStatus {
export const ToolCallSchema = z.object({
id: z.string(),
name: z.string(),
status: z.nativeEnum(ToolCallStatus),
parameters: z.record(z.any()),
status: z.enum(ToolCallStatus),
parameters: z.record(z.string(), z.any()),
result: z.any().optional(),
error: z.string().optional(),
startTime: z.number(),
Expand Down Expand Up @@ -76,7 +76,7 @@ export const AgentTaskSchema = z.object({
id: z.string(),
title: z.string(),
description: z.string().optional(),
status: z.nativeEnum(TaskStatus),
status: z.enum(TaskStatus),
priority: z.enum(['low', 'medium', 'high', 'critical']).optional(),
parentTaskId: z.string().optional(),
dependsOn: z.array(z.string()).optional(),
Expand All @@ -100,7 +100,7 @@ export const AgentTaskSchema = z.object({
* Agent state schema
*/
export const AgentStateSchema = z.object({
phase: z.nativeEnum(AgentPhase),
phase: z.enum(AgentPhase),
currentTask: AgentTaskSchema.optional(),
taskQueue: z.array(AgentTaskSchema),
completedTasks: z.array(AgentTaskSchema),
Expand Down Expand Up @@ -153,7 +153,7 @@ export const AgentCapabilitySchema = z.object({
*/
export const AgentMetricsSchema = z.object({
timestamp: z.number(),
phase: z.nativeEnum(AgentPhase),
phase: z.enum(AgentPhase),
activeTasks: z.number(),
completedTasks: z.number(),
failedTasks: z.number(),
Expand Down Expand Up @@ -354,9 +354,7 @@ export function calculateAgentStatistics(state: AgentState): AgentState['statist
const failedTasks = allTasks.filter((t) => t.status === TaskStatus.FAILED);

const allToolCalls = allTasks.flatMap((t) => t.toolCalls ?? []);
const successfulToolCalls = allToolCalls.filter(
(tc) => tc.status === ToolCallStatus.COMPLETED
);
const successfulToolCalls = allToolCalls.filter((tc) => tc.status === ToolCallStatus.COMPLETED);
const failedToolCalls = allToolCalls.filter((tc) => tc.status === ToolCallStatus.FAILED);

const taskDurations = completedTasks
Expand Down
11 changes: 4 additions & 7 deletions src/types/conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const WorkspaceConfigSchema = z.object({
gitBranch: z.string().optional(),
excludePatterns: z.array(z.string()).optional(),
includePatterns: z.array(z.string()).optional(),
customSettings: z.record(z.any()).optional(),
customSettings: z.record(z.string(), z.any()).optional(),
});

/**
Expand Down Expand Up @@ -65,7 +65,7 @@ export const ConversationSchema = ConversationMetaSchema.extend({
files: z.array(z.string()).optional(),
activeTasks: z.array(z.string()).optional(),
pinnedFiles: z.array(z.string()).optional(),
environment: z.record(z.string()).optional(),
environment: z.record(z.string(), z.string()).optional(),
})
.optional(),
settings: z
Expand Down Expand Up @@ -183,17 +183,14 @@ export function filterConversations(
}

if (filter.tags && filter.tags.length > 0) {
filtered = filtered.filter((c) =>
filter.tags?.some((tag) => c.tags?.includes(tag)) ?? false
);
filtered = filtered.filter((c) => filter.tags?.some((tag) => c.tags?.includes(tag)) ?? false);
}

if (filter.searchQuery) {
const query = filter.searchQuery.toLowerCase();
filtered = filtered.filter(
(c) =>
c.title.toLowerCase().includes(query) ||
c.lastMessagePreview?.toLowerCase().includes(query)
c.title.toLowerCase().includes(query) || c.lastMessagePreview?.toLowerCase().includes(query)
);
}

Expand Down
12 changes: 4 additions & 8 deletions src/types/diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export enum DiffChangeType {
* Diff line schema
*/
export const DiffLineSchema = z.object({
type: z.nativeEnum(DiffLineType),
type: z.enum(DiffLineType),
content: z.string(),
oldLineNumber: z.number().optional(),
newLineNumber: z.number().optional(),
Expand All @@ -53,7 +53,7 @@ export const DiffHunkSchema = z.object({
export const FileDiffSchema = z.object({
oldPath: z.string(),
newPath: z.string(),
changeType: z.nativeEnum(DiffChangeType),
changeType: z.enum(DiffChangeType),
hunks: z.array(DiffHunkSchema),
additions: z.number(),
deletions: z.number(),
Expand All @@ -77,7 +77,7 @@ export const DiffSummarySchema = z.object({
path: z.string(),
additions: z.number(),
deletions: z.number(),
changeType: z.nativeEnum(DiffChangeType),
changeType: z.enum(DiffChangeType),
})
),
});
Expand Down Expand Up @@ -304,11 +304,7 @@ export function collapseDiffHunks(hunks: DiffHunk[], minGapSize = 3): DiffHunk[]
)
);

const combinedLines: DiffLine[] = [
...current.lines,
...gapLines,
...next.lines,
];
const combinedLines: DiffLine[] = [...current.lines, ...gapLines, ...next.lines];

const newOldLines = next.oldStart + next.oldLines - current.oldStart;
const newNewLines = next.newStart + next.newLines - current.newStart;
Expand Down
11 changes: 7 additions & 4 deletions src/types/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const FileMetadataSchema = z.object({
export const FileChangeSchema = z.object({
id: z.string(),
path: z.string(),
status: z.nativeEnum(FileStatus),
status: z.enum(FileStatus),
oldPath: z.string().optional(), // For rename/move operations
timestamp: z.number(),
changes: z
Expand All @@ -76,7 +76,7 @@ export const FileChangeSchema = z.object({
*/
export const FileOperationSchema = z.object({
id: z.string(),
type: z.nativeEnum(FileOperationType),
type: z.enum(FileOperationType),
path: z.string(),
timestamp: z.number(),
status: z.enum(['pending', 'in_progress', 'completed', 'failed']),
Expand Down Expand Up @@ -146,7 +146,7 @@ export const FileSearchResultSchema = z.object({
*/
export const FileDiffStatsSchema = z.object({
path: z.string(),
status: z.nativeEnum(FileStatus),
status: z.enum(FileStatus),
additions: z.number(),
deletions: z.number(),
changes: z.number(),
Expand Down Expand Up @@ -293,7 +293,10 @@ export function sortFileTreeNodes(nodes: FileTreeNode[]): FileTreeNode[] {
});
}

export function flattenFileTree(node: FileTreeNode, depth = 0): (FileTreeNode & { depth: number })[] {
export function flattenFileTree(
node: FileTreeNode,
depth = 0
): (FileTreeNode & { depth: number })[] {
const result: (FileTreeNode & { depth: number })[] = [{ ...node, depth }];

if (node.children && node.expanded) {
Expand Down
4 changes: 2 additions & 2 deletions src/types/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const ToolCallContentSchema = z.object({
type: z.literal(MessageContentType.TOOL_CALL),
toolName: z.string(),
toolCallId: z.string(),
parameters: z.record(z.any()),
parameters: z.record(z.string(), z.any()),
});

/**
Expand Down Expand Up @@ -118,7 +118,7 @@ export const ChatBaseMessageSchema = z.object({
id: z.string(),
conversationId: z.string(),
timestamp: z.number(),
status: z.nativeEnum(MessageStatus),
status: z.enum(MessageStatus),
content: z.array(MessageContentSchema),
metadata: z
.object({
Expand Down
32 changes: 23 additions & 9 deletions src/types/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { z } from 'zod';
// SHARED PRIMITIVES
// ═══════════════════════════════════════════════════════════════

const UUIDSchema = z.string().uuid();
const UUIDSchema = z.uuid();
const SessionIdSchema = z.string().min(1);

// Input mode: default (ask permission), accept (auto-approve), plan (read-only)
Expand Down Expand Up @@ -32,7 +32,7 @@ export const ElementContextSchema = z.object({
componentName: z.string(),
filePath: z.string(),
lineNumber: z.number(),
props: z.record(z.unknown()),
props: z.record(z.string(), z.unknown()),
componentStack: z.array(z.string()),
tagName: z.string(),
selector: z.string(),
Expand Down Expand Up @@ -124,7 +124,7 @@ export const AgentStartSchema = z.object({
uuid: UUIDSchema,
session_id: SessionIdSchema,
task: z.string(),
context: z.record(z.unknown()).optional(),
context: z.record(z.string(), z.unknown()).optional(),
});

export const AgentStopSchema = z.object({
Expand Down Expand Up @@ -277,7 +277,7 @@ export const DiffOpenSchema = z.object({
export const UrlOpenSchema = z.object({
type: z.literal('url:open'),
uuid: UUIDSchema,
url: z.string().url(),
url: z.url(),
});

// Permission response (webview → extension)
Expand Down Expand Up @@ -674,7 +674,7 @@ export const ToolStartSchema = z.object({
message_id: z.string(),
tool_id: z.string(),
tool_name: z.string(),
tool_input: z.record(z.unknown()),
tool_input: z.record(z.string(), z.unknown()),
});

export const ToolEndSchema = z.object({
Expand All @@ -695,7 +695,7 @@ export const PermissionRequestSchema = z.object({
session_id: SessionIdSchema,
request_id: z.string(),
tool_name: z.string(),
tool_input: z.record(z.unknown()),
tool_input: z.record(z.string(), z.unknown()),
});

// Input mode changed (from extension to webview)
Expand Down Expand Up @@ -969,7 +969,7 @@ export const ReactElementContextSchema = z.object({
componentName: z.string(),
filePath: z.string(),
lineNumber: z.number(),
props: z.record(z.unknown()),
props: z.record(z.string(), z.unknown()),
componentStack: z.array(z.string()),
// DOM info
tagName: z.string(),
Expand Down Expand Up @@ -1366,13 +1366,27 @@ export function isProtocolTerminalMessage(

export function isProtocolFileMessage(
msg: ExtensionMessage
): msg is FileContent | FileChanged | FileWritten | FileTreeResponse | FileTreeError | FileListResponse {
): msg is
| FileContent
| FileChanged
| FileWritten
| FileTreeResponse
| FileTreeError
| FileListResponse {
return msg.type.startsWith('file:');
}

export function isProtocolBrowserMessage(
msg: ExtensionMessage
): msg is BrowserCreated | BrowserNavigated | BrowserElementSelected | BrowserLoading | BrowserError | BrowserDestroyed | BrowserOpen | BrowserClose {
): msg is
| BrowserCreated
| BrowserNavigated
| BrowserElementSelected
| BrowserLoading
| BrowserError
| BrowserDestroyed
| BrowserOpen
| BrowserClose {
return msg.type.startsWith('browser:');
}

Expand Down
Loading