Skip to content
Draft
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
36 changes: 23 additions & 13 deletions src/main/clipboard-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,23 +42,27 @@ let lastClipboardText = '';
let lastClipboardImage: Buffer | null = null;
let pollInterval: NodeJS.Timeout | null = null;
let isEnabled = true;
let pendingSave: NodeJS.Timeout | null = null;

// ─── Paths ──────────────────────────────────────────────────────────

function getClipboardDir(): string {
const dir = path.join(app.getPath('userData'), 'clipboard-history');
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
return dir;
return path.join(app.getPath('userData'), 'clipboard-history');
}

function getImagesDir(): string {
const dir = path.join(getClipboardDir(), 'images');
return path.join(getClipboardDir(), 'images');
}

function ensureClipboardDirs(): void {
const dir = getClipboardDir();
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
return dir;
const imagesDir = getImagesDir();
if (!fs.existsSync(imagesDir)) {
fs.mkdirSync(imagesDir, { recursive: true });
}
}

function getHistoryFilePath(): string {
Expand Down Expand Up @@ -105,12 +109,15 @@ function loadHistory(): void {
}

function saveHistory(): void {
try {
const historyPath = getHistoryFilePath();
fs.writeFileSync(historyPath, JSON.stringify(clipboardHistory, null, 2));
} catch (e) {
console.error('Failed to save clipboard history:', e);
}
if (pendingSave) clearTimeout(pendingSave);
pendingSave = setTimeout(() => {
try {
const historyPath = getHistoryFilePath();
fs.writeFileSync(historyPath, JSON.stringify(clipboardHistory, null, 2));
} catch (e) {
console.error('Failed to save clipboard history:', e);
}
}, 100); // Batch writes within 100ms
}

// ─── Clipboard Monitoring ───────────────────────────────────────────
Expand Down Expand Up @@ -277,6 +284,9 @@ function pollClipboard(): void {
// ─── Public API ─────────────────────────────────────────────────────

export function startClipboardMonitor(): void {
// Ensure directories exist once at startup
ensureClipboardDirs();

loadHistory();

// Initial read
Expand Down
15 changes: 10 additions & 5 deletions src/main/memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const MAX_TOP_K = 20;
const MAX_MEMORY_ITEM_CHARS = 320;
const MAX_MEMORY_CONTEXT_CHARS = 2400;

let pendingMemorySave: NodeJS.Timeout | null = null;

// ─── Local File-Based Memory Store ──────────────────────────────────────────
// Used as a fallback when Supermemory is not configured. Persists to
// <userData>/local-memories.json so memories survive restarts.
Expand All @@ -37,11 +39,14 @@ function readLocalMemories(): LocalMemoryEntry[] {
}

function writeLocalMemories(memories: LocalMemoryEntry[]): void {
try {
fs.writeFileSync(getLocalMemoryPath(), JSON.stringify(memories, null, 2), 'utf8');
} catch (err) {
console.error('[LocalMemory] Failed to write memories:', err);
}
if (pendingMemorySave) clearTimeout(pendingMemorySave);
pendingMemorySave = setTimeout(() => {
try {
fs.writeFileSync(getLocalMemoryPath(), JSON.stringify(memories, null, 2), 'utf8');
} catch (err) {
console.error('[LocalMemory] Failed to write memories:', err);
}
}, 100); // Batch writes within 100ms
}

function addLocalMemory(text: string): { id: string } {
Expand Down
29 changes: 24 additions & 5 deletions src/main/settings-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,21 @@ export function saveSettings(patch: Partial<AppSettings>): AppSettings {
return { ...updated };
}

export async function saveSettingsAsync(patch: Partial<AppSettings>): Promise<AppSettings> {
const current = loadSettings();
const updated = { ...current, ...patch };
settingsCache = updated;

// Fire-and-forget async write
try {
await fs.promises.writeFile(getSettingsPath(), JSON.stringify(updated, null, 2));
} catch (e) {
console.error('Failed to save settings:', e);
}

return { ...updated };
}

export function resetSettingsCache(): void {
settingsCache = null;
}
Expand All @@ -185,6 +200,7 @@ interface OAuthTokenEntry {
}

let oauthTokensCache: Record<string, OAuthTokenEntry> | null = null;
let pendingOAuthSave: NodeJS.Timeout | null = null;

function getOAuthTokensPath(): string {
return path.join(app.getPath('userData'), 'oauth-tokens.json');
Expand All @@ -203,11 +219,14 @@ function loadOAuthTokens(): Record<string, OAuthTokenEntry> {

function saveOAuthTokens(tokens: Record<string, OAuthTokenEntry>): void {
oauthTokensCache = tokens;
try {
fs.writeFileSync(getOAuthTokensPath(), JSON.stringify(tokens, null, 2));
} catch (e) {
console.error('Failed to save OAuth tokens:', e);
}
if (pendingOAuthSave) clearTimeout(pendingOAuthSave);
pendingOAuthSave = setTimeout(() => {
try {
fs.writeFileSync(getOAuthTokensPath(), JSON.stringify(tokens, null, 2));
} catch (e) {
console.error('Failed to save OAuth tokens:', e);
}
}, 100); // Batch writes within 100ms
}

export function setOAuthToken(provider: string, token: OAuthTokenEntry): void {
Expand Down
24 changes: 16 additions & 8 deletions src/main/snippet-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,19 @@ export interface Snippet {
}

let snippetsCache: Snippet[] | null = null;
let pendingSave: NodeJS.Timeout | null = null;

// ─── Paths ──────────────────────────────────────────────────────────

function getSnippetsDir(): string {
const dir = path.join(app.getPath('userData'), 'snippets');
return path.join(app.getPath('userData'), 'snippets');
}

function ensureSnippetsDir(): void {
const dir = getSnippetsDir();
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
return dir;
}

function getSnippetsFilePath(): string {
Expand Down Expand Up @@ -66,17 +70,21 @@ function loadFromDisk(): Snippet[] {
}

function saveToDisk(): void {
try {
const filePath = getSnippetsFilePath();
fs.writeFileSync(filePath, JSON.stringify(snippetsCache || [], null, 2), 'utf-8');
} catch (e) {
console.error('Failed to save snippets to disk:', e);
}
if (pendingSave) clearTimeout(pendingSave);
pendingSave = setTimeout(() => {
try {
const filePath = getSnippetsFilePath();
fs.writeFileSync(filePath, JSON.stringify(snippetsCache || [], null, 2), 'utf-8');
} catch (e) {
console.error('Failed to save snippets to disk:', e);
}
}, 100); // Batch writes within 100ms
}

// ─── Public API ─────────────────────────────────────────────────────

export function initSnippetStore(): void {
ensureSnippetsDir();
snippetsCache = loadFromDisk();
console.log(`[Snippets] Loaded ${snippetsCache.length} snippet(s)`);
}
Expand Down