Merge commit 'fe6f830eab' into dev_mod

This commit is contained in:
DESKTOP-RTLN3BA\$punk 2026-04-08 16:21:36 -07:00
commit 5891dfa4d0
26 changed files with 1674 additions and 314 deletions

View file

@ -30,6 +30,8 @@ export const IPC_CHANNELS = {
FOLDER_SYNC_RENDERER_READY: 'folder-sync:renderer-ready',
FOLDER_SYNC_GET_PENDING_EVENTS: 'folder-sync:get-pending-events',
FOLDER_SYNC_ACK_EVENTS: 'folder-sync:ack-events',
FOLDER_SYNC_LIST_FILES: 'folder-sync:list-files',
FOLDER_SYNC_SEED_MTIMES: 'folder-sync:seed-mtimes',
BROWSE_FILES: 'browse:files',
READ_LOCAL_FILES: 'browse:read-local-files',
// Auth token sync across windows

View file

@ -19,6 +19,9 @@ import {
markRendererReady,
browseFiles,
readLocalFiles,
listFolderFiles,
seedFolderMtimes,
type WatchedFolderConfig,
} from '../modules/folder-watcher';
import { getShortcuts, setShortcuts, type ShortcutConfig } from '../modules/shortcuts';
import { getActiveSearchSpaceId, setActiveSearchSpaceId } from '../modules/active-search-space';
@ -91,6 +94,16 @@ export function registerIpcHandlers(): void {
acknowledgeFileEvents(eventIds)
);
ipcMain.handle(IPC_CHANNELS.FOLDER_SYNC_LIST_FILES, (_event, config: WatchedFolderConfig) =>
listFolderFiles(config)
);
ipcMain.handle(
IPC_CHANNELS.FOLDER_SYNC_SEED_MTIMES,
(_event, folderPath: string, mtimes: Record<string, number>) =>
seedFolderMtimes(folderPath, mtimes),
);
ipcMain.handle(IPC_CHANNELS.BROWSE_FILES, () => browseFiles());
ipcMain.handle(IPC_CHANNELS.READ_LOCAL_FILES, (_event, paths: string[]) =>

View file

@ -188,6 +188,31 @@ function walkFolderMtimes(config: WatchedFolderConfig): MtimeMap {
return result;
}
export interface FolderFileEntry {
relativePath: string;
fullPath: string;
size: number;
mtimeMs: number;
}
export function listFolderFiles(config: WatchedFolderConfig): FolderFileEntry[] {
const root = config.path;
const mtimeMap = walkFolderMtimes(config);
const entries: FolderFileEntry[] = [];
for (const [relativePath, mtimeMs] of Object.entries(mtimeMap)) {
const fullPath = path.join(root, relativePath);
try {
const stat = fs.statSync(fullPath);
entries.push({ relativePath, fullPath, size: stat.size, mtimeMs });
} catch {
// File may have been removed between walk and stat
}
}
return entries;
}
function getMainWindow(): BrowserWindow | null {
const windows = BrowserWindow.getAllWindows();
return windows.length > 0 ? windows[0] : null;
@ -424,14 +449,30 @@ export async function acknowledgeFileEvents(eventIds: string[]): Promise<{ ackno
const ackSet = new Set(eventIds);
let acknowledged = 0;
const foldersToUpdate = new Set<string>();
for (const [key, event] of outboxEvents.entries()) {
if (ackSet.has(event.id)) {
if (event.action !== 'unlink') {
const map = mtimeMaps.get(event.folderPath);
if (map) {
try {
map[event.relativePath] = fs.statSync(event.fullPath).mtimeMs;
foldersToUpdate.add(event.folderPath);
} catch {
// File may have been removed
}
}
}
outboxEvents.delete(key);
acknowledged += 1;
}
}
for (const fp of foldersToUpdate) {
persistMtimeMap(fp);
}
if (acknowledged > 0) {
persistOutbox();
}
@ -439,6 +480,17 @@ export async function acknowledgeFileEvents(eventIds: string[]): Promise<{ ackno
return { acknowledged };
}
export async function seedFolderMtimes(
folderPath: string,
mtimes: Record<string, number>,
): Promise<void> {
const ms = await getMtimeStore();
const existing: MtimeMap = ms.get(folderPath) ?? {};
const merged = { ...existing, ...mtimes };
mtimeMaps.set(folderPath, merged);
ms.set(folderPath, merged);
}
export async function pauseWatcher(): Promise<void> {
for (const [, entry] of watchers) {
if (entry.watcher) {

View file

@ -64,6 +64,9 @@ contextBridge.exposeInMainWorld('electronAPI', {
signalRendererReady: () => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_RENDERER_READY),
getPendingFileEvents: () => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_GET_PENDING_EVENTS),
acknowledgeFileEvents: (eventIds: string[]) => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_ACK_EVENTS, eventIds),
listFolderFiles: (config: any) => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_LIST_FILES, config),
seedFolderMtimes: (folderPath: string, mtimes: Record<string, number>) =>
ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_SEED_MTIMES, folderPath, mtimes),
// Browse files via native dialog
browseFiles: () => ipcRenderer.invoke(IPC_CHANNELS.BROWSE_FILES),