Skip to content

Commit a3a0583

Browse files
committed
fix linting and errors
1 parent a2fe416 commit a3a0583

File tree

19 files changed

+410
-49
lines changed

19 files changed

+410
-49
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
"@dnd-kit/react": "^0.1.21",
7474
"@floating-ui/dom": "^1.7.4",
7575
"@phosphor-icons/react": "^2.1.10",
76-
"@posthog/agent": "1.21.1",
76+
"@posthog/agent": "1.22.0",
7777
"@radix-ui/react-icons": "^1.3.2",
7878
"@radix-ui/themes": "^3.2.1",
7979
"@tanstack/react-query": "^5.90.2",

pnpm-lock.yaml

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,13 @@ function createWindow(): void {
143143
{ role: "zoomOut" },
144144
{ type: "separator" },
145145
{ role: "togglefullscreen" },
146+
{ type: "separator" },
147+
{
148+
label: "Reset layout",
149+
click: () => {
150+
mainWindow?.webContents.send("reset-layout");
151+
},
152+
},
146153
],
147154
},
148155
];

src/main/preload.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ contextBridge.exposeInMainWorld("electronAPI", {
127127
query?: string,
128128
): Promise<Array<{ path: string; name: string }>> =>
129129
ipcRenderer.invoke("list-repo-files", repoPath, query),
130+
clearRepoFileCache: (repoPath: string): Promise<void> =>
131+
ipcRenderer.invoke("clear-repo-file-cache", repoPath),
130132
agentStart: async (
131133
params: AgentStartParams,
132134
): Promise<{ taskId: string; channel: string }> =>
@@ -217,6 +219,11 @@ contextBridge.exposeInMainWorld("electronAPI", {
217219
ipcRenderer.on("new-task", wrapped);
218220
return () => ipcRenderer.removeListener("new-task", wrapped);
219221
},
222+
onResetLayout: (listener: () => void): (() => void) => {
223+
const wrapped = () => listener();
224+
ipcRenderer.on("reset-layout", wrapped);
225+
return () => ipcRenderer.removeListener("reset-layout", wrapped);
226+
},
220227
getAppVersion: (): Promise<string> => ipcRenderer.invoke("app:get-version"),
221228
onUpdateReady: (listener: () => void): (() => void) => {
222229
const channel = "updates:ready";

src/main/services/fs.ts

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ import fs from "node:fs";
33
import path from "node:path";
44
import { promisify } from "node:util";
55
import { type IpcMainInvokeEvent, ipcMain } from "electron";
6+
import { getChangedFilesForRepo } from "./git";
67

78
const execAsync = promisify(exec);
89
const fsPromises = fs.promises;
910

1011
interface FileEntry {
1112
path: string;
1213
name: string;
14+
changed?: boolean;
1315
}
1416

1517
// Cache for repository files to avoid rescanning
@@ -41,6 +43,7 @@ async function listFilesRecursive(
4143
dirPath: string,
4244
ignoredFiles: Set<string>,
4345
baseDir: string,
46+
changedFiles: Set<string>,
4447
): Promise<FileEntry[]> {
4548
const files: FileEntry[] = [];
4649

@@ -51,9 +54,9 @@ async function listFilesRecursive(
5154
const fullPath = path.join(dirPath, entry.name);
5255
const relativePath = path.relative(baseDir, fullPath);
5356

54-
// Skip hidden files/directories, node_modules, and common build dirs
57+
// Skip .git directory, node_modules, and common build dirs
5558
if (
56-
entry.name.startsWith(".") ||
59+
entry.name === ".git" ||
5760
entry.name === "node_modules" ||
5861
entry.name === "dist" ||
5962
entry.name === "build" ||
@@ -72,12 +75,14 @@ async function listFilesRecursive(
7275
fullPath,
7376
ignoredFiles,
7477
baseDir,
78+
changedFiles,
7579
);
7680
files.push(...subFiles);
7781
} else if (entry.isFile()) {
7882
files.push({
7983
path: relativePath,
8084
name: entry.name,
85+
changed: changedFiles.has(relativePath),
8186
});
8287
}
8388
}
@@ -112,8 +117,16 @@ export function registerFsIpc(): void {
112117
// Get git-ignored files
113118
const ignoredFiles = await getGitIgnoredFiles(repoPath);
114119

120+
// Get changed files from git
121+
const changedFiles = await getChangedFilesForRepo(repoPath);
122+
115123
// List all files
116-
allFiles = await listFilesRecursive(repoPath, ignoredFiles, repoPath);
124+
allFiles = await listFilesRecursive(
125+
repoPath,
126+
ignoredFiles,
127+
repoPath,
128+
changedFiles,
129+
);
117130

118131
// Update cache
119132
repoFileCache.set(repoPath, {
@@ -131,17 +144,26 @@ export function registerFsIpc(): void {
131144
f.path.toLowerCase().includes(lowerQuery) ||
132145
f.name.toLowerCase().includes(lowerQuery),
133146
)
134-
.slice(0, 50); // Limit results
147+
.slice(0, 50); // Limit search results
135148
}
136149

137-
return allFiles.slice(0, 100); // Limit initial results
150+
return allFiles; // Return all files for full tree view
138151
} catch (error) {
139152
console.error("Error listing repo files:", error);
140153
return [];
141154
}
142155
},
143156
);
144157

158+
ipcMain.handle(
159+
"clear-repo-file-cache",
160+
async (_event: IpcMainInvokeEvent, repoPath: string): Promise<void> => {
161+
if (repoPath) {
162+
repoFileCache.delete(repoPath);
163+
}
164+
},
165+
);
166+
145167
// Plan file operations
146168
ipcMain.handle(
147169
"ensure-posthog-folder",

src/main/services/git.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,75 @@ const getCurrentBranch = async (
9393
}
9494
};
9595

96+
const getDefaultBranch = async (directoryPath: string): Promise<string> => {
97+
try {
98+
// Try to get the default branch from origin
99+
const { stdout } = await execAsync(
100+
"git symbolic-ref refs/remotes/origin/HEAD",
101+
{ cwd: directoryPath },
102+
);
103+
const branch = stdout.trim().replace("refs/remotes/origin/", "");
104+
return branch;
105+
} catch {
106+
// Fallback: check if main or master exists
107+
try {
108+
await execAsync("git rev-parse --verify main", {
109+
cwd: directoryPath,
110+
});
111+
return "main";
112+
} catch {
113+
return "master";
114+
}
115+
}
116+
};
117+
118+
const getChangedFiles = async (directoryPath: string): Promise<Set<string>> => {
119+
const changedFiles = new Set<string>();
120+
121+
try {
122+
const defaultBranch = await getDefaultBranch(directoryPath);
123+
const currentBranch = await getCurrentBranch(directoryPath);
124+
125+
// Don't show changes if we're on the default branch
126+
if (currentBranch === defaultBranch) {
127+
return changedFiles;
128+
}
129+
130+
// Get files that differ from default branch
131+
try {
132+
const { stdout: diffFiles } = await execAsync(
133+
`git diff --name-only ${defaultBranch}...HEAD`,
134+
{ cwd: directoryPath },
135+
);
136+
const files = diffFiles.trim().split("\n").filter(Boolean);
137+
for (const file of files) {
138+
changedFiles.add(file);
139+
}
140+
} catch {
141+
// Branch might not exist or no common ancestor, skip
142+
}
143+
144+
// Get modified files in working directory
145+
const { stdout: statusFiles } = await execAsync("git status --porcelain", {
146+
cwd: directoryPath,
147+
});
148+
const lines = statusFiles.trim().split("\n").filter(Boolean);
149+
for (const line of lines) {
150+
// Parse git status format: XY filename
151+
const fileName = line.substring(3).trim();
152+
if (fileName) {
153+
changedFiles.add(fileName);
154+
}
155+
}
156+
} catch (error) {
157+
console.error("Error getting changed files:", error);
158+
}
159+
160+
return changedFiles;
161+
};
162+
163+
export const getChangedFilesForRepo = getChangedFiles;
164+
96165
export const findReposDirectory = async (): Promise<string | null> => {
97166
const platform = os.platform();
98167

src/renderer/components/MainLayout.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { StatusBar } from "@components/StatusBar";
33
import { UpdatePrompt } from "@components/UpdatePrompt";
44
import { TopBar } from "@components/ui/topnav/TopBar";
55
import { CommandMenu } from "@features/command/components/CommandMenu";
6+
import { usePanelLayoutStore } from "@features/panels/store/panelLayoutStore";
67
import { SettingsView } from "@features/settings/components/SettingsView";
78
import { TaskDetail } from "@features/task-detail/components/TaskDetail";
89
import { TaskInput } from "@features/task-detail/components/TaskInput";
@@ -24,6 +25,7 @@ export function MainLayout() {
2425
goBack,
2526
goForward,
2627
} = useNavigationStore();
28+
const clearAllLayouts = usePanelLayoutStore((state) => state.clearAllLayouts);
2729
useIntegrations();
2830
const [commandMenuOpen, setCommandMenuOpen] = useState(false);
2931

@@ -35,6 +37,11 @@ export function MainLayout() {
3537
navigateToTaskInput();
3638
}, [navigateToTaskInput]);
3739

40+
const handleResetLayout = useCallback(() => {
41+
clearAllLayouts();
42+
window.location.reload();
43+
}, [clearAllLayouts]);
44+
3845
useHotkeys("mod+k", () => setCommandMenuOpen((prev) => !prev), {
3946
enabled: !commandMenuOpen,
4047
});
@@ -58,11 +65,16 @@ export function MainLayout() {
5865
handleFocusTaskMode();
5966
});
6067

68+
const unsubscribeResetLayout = window.electronAPI?.onResetLayout(() => {
69+
handleResetLayout();
70+
});
71+
6172
return () => {
6273
unsubscribeSettings?.();
6374
unsubscribeNewTask?.();
75+
unsubscribeResetLayout?.();
6476
};
65-
}, [handleOpenSettings, handleFocusTaskMode]);
77+
}, [handleOpenSettings, handleFocusTaskMode, handleResetLayout]);
6678

6779
const handleSelectTask = (task: Task) => {
6880
navigateToTask(task);

0 commit comments

Comments
 (0)