Feature/lmstudio provider (#30)

* chore: just a plan update

* Add LM Studio as local AI provider (OpenAI-compatible, like Ollama)

* Convert WebP thumbnails to JPEG before image analysis for LM Studio compatibility

* Strengthen language enforcement in image analysis prompt for local models

* Use i18n localized prompts for image analysis instead of English instructions

* Add airplane mode (Flugmodus) with status bar toggle and offline model preferences

* Fix flightmode: persist model IDs, skip network when offline, airplane icon

* Auto-fallback to offline models in airplane mode for chat, title, and image analysis

* Auto-select first local model as offline fallback when no explicit offline model configured

* Block git fetch/pull/push and site upload in airplane mode

* fix: thumbnails optimized for AI

* fix: error handling in airplane mode

---------

Co-authored-by: hugo <hugoms@me.com>
This commit is contained in:
Georg Bauer
2026-03-02 13:35:42 +01:00
committed by GitHub
parent 4b4a9c1c8b
commit 5747925503
34 changed files with 2215 additions and 105 deletions

View File

@@ -1098,4 +1098,30 @@ describe('GitSidebar', () => {
vi.useRealTimers();
}
});
it.each(['fetch', 'pull', 'push'] as const)('shows error modal instead of inline error when %s returns offline code', async (action) => {
(window as any).electronAPI.git.getRepoState = vi.fn().mockResolvedValue({
isRepo: true,
rootPath: '/repo/path',
currentBranch: 'main',
hasRemote: true,
});
(window as any).electronAPI.git[action] = vi.fn().mockResolvedValue({ success: false, code: 'offline' });
render(<GitSidebar />);
const button = await screen.findByRole('button', { name: new RegExp(`^${action}$`, 'i') });
await act(async () => {
fireEvent.click(button);
});
// Should set errorModal in the store
const store = getStore();
expect(store.errorModal).not.toBeNull();
expect(store.errorModal!.message).toBe('This action is blocked while airplane mode is active.');
// Should NOT show inline error in the sidebar
expect(screen.queryByText('This action is blocked while airplane mode is active.')).not.toBeInTheDocument();
});
});