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
19 changes: 0 additions & 19 deletions packages/desktop/scripts/verify.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,6 @@ console.log('Screenshot (Agent mode):', shot1)
const bodyText = await page.evaluate(() => document.body.innerText)
console.log('Page text:', bodyText.slice(0, 200))

// Click the mode switch button
const switchResult = await page.evaluate(() => {
const btns = [...document.querySelectorAll('button')]
const btn = btns.find(b => b.textContent?.includes('IDE'))
if (!btn) return 'NOT_FOUND'
btn.click()
return 'CLICKED: ' + btn.textContent?.trim()
})
console.log('Switch button:', switchResult)

await new Promise(r => setTimeout(r, 500))
const shot2 = path.join(SHOT_DIR, '02-ide-mode.png')
await page.screenshot({ path: shot2 })
console.log('Screenshot (IDE mode):', shot2)

// Verify mode switched
const bodyText2 = await page.evaluate(() => document.body.innerText)
console.log('Page text after switch:', bodyText2.slice(0, 200))

// Test IPC ping
const pingResult = await page.evaluate(() => {
return window.electronAPI?.ping?.()
Expand Down
37 changes: 28 additions & 9 deletions packages/desktop/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { useEffect } from 'react';
import { useAgentCore } from './hooks/useAgent';
import { useUIStore } from './stores/ui.store';
import { useWorkspaceStore } from './stores/workspace.store';
import AgentLayout from './layouts/AgentLayout';
import IDELayout from './layouts/IDELayout';
import ProjectStrip from './agent/ProjectStrip';
import AgentSidebar from './agent/AgentSidebar';
import AgentWorkspace from './agent/AgentWorkspace';
import { AutomationPanel } from './agent/AutomationPanel';
import GlobalSettingsPage from './settings/GlobalSettingsPage';
import ProjectSettingsPage from './settings/ProjectSettingsPage';
import TitleBar from './TitleBar';
import ErrorBoundary from './shared/ErrorBoundary';

export default function App() {
const mode = useUIStore((s) => s.mode);
const { sendMessage, abort } = useAgentCore();
const theme = useUIStore((s) => s.theme);
const view = useUIStore((s) => s.view);
const rootPath = useWorkspaceStore((s) => s.rootPath);

// Sync workspace cwd to main process for git polling
Expand All @@ -31,16 +37,29 @@ export default function App() {
};
}, []);

let content;
if (view === 'global-settings') {
content = <GlobalSettingsPage />;
} else if (view === 'project-settings') {
content = <ProjectSettingsPage />;
} else if (view === 'automation') {
content = <AutomationPanel />;
} else {
content = (
<div className="flex flex-1 min-h-0 overflow-hidden">
<ProjectStrip />
<AgentSidebar />
<AgentWorkspace sendMessage={sendMessage} abort={abort} />
</div>
);
}

return (
<ErrorBoundary>
<div className="h-screen flex flex-col bg-[var(--bg-base)] text-[var(--text-primary)] overflow-hidden">
<TitleBar />
{/* Both layouts stay mounted; visibility toggled via display to preserve Monaco + PTY state */}
<div className={`${mode === 'agent' ? 'flex' : 'hidden'} flex-1 flex-col overflow-hidden`}>
<AgentLayout />
</div>
<div className={`${mode === 'ide' ? 'flex' : 'hidden'} flex-1 flex-col overflow-hidden`}>
<IDELayout />
<div className="flex flex-1 flex-col overflow-hidden">
{content}
</div>
</div>
</ErrorBoundary>
Expand Down
34 changes: 1 addition & 33 deletions packages/desktop/src/TitleBar.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
import { useUIStore } from './stores/ui.store';

const isWindows = window.electronAPI?.platform === 'win32';

export default function TitleBar() {
const mode = useUIStore((s) => s.mode);
const setMode = useUIStore((s) => s.setMode);

if (!isWindows) return null;
if (window.electronAPI?.platform !== 'win32') return null;

return (
<div
Expand All @@ -19,31 +12,6 @@ export default function TitleBar() {
}
>
<span className="text-[var(--text-tertiary)] text-xs font-medium">Coding Code</span>
<div
className="flex items-center gap-0.5 ml-4"
style={{ WebkitAppRegion: 'no-drag' } as React.CSSProperties}
>
<button
onClick={() => setMode('agent')}
className={`px-3 h-6 text-xs rounded transition-colors ${
mode === 'agent'
? 'bg-[var(--accent-primary)] text-[var(--text-inverse)]'
: 'text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)]'
}`}
>
Agent
</button>
<button
onClick={() => setMode('ide')}
className={`px-3 h-6 text-xs rounded transition-colors ${
mode === 'ide'
? 'bg-[var(--accent-primary)] text-[var(--text-inverse)]'
: 'text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)]'
}`}
>
IDE
</button>
</div>
</div>
);
}
33 changes: 0 additions & 33 deletions packages/desktop/src/layouts/AgentLayout.tsx

This file was deleted.

18 changes: 0 additions & 18 deletions packages/desktop/src/layouts/IDELayout.tsx

This file was deleted.

14 changes: 0 additions & 14 deletions packages/desktop/src/stores/ui.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,33 @@ import { immer } from 'zustand/middleware/immer';
import { createDebouncedStorage } from './storage';

interface UIState {
mode: 'agent' | 'ide';
view: 'agent' | 'global-settings' | 'project-settings' | 'automation';
sidebarCollapsed: boolean;
sidebarWidth: number;
rightPanelWidth: number;
bottomPanelHeight: number;
ideSidebarView: 'explorer' | 'search' | 'git' | 'extensions';
theme: 'dark' | 'light' | 'paper';
}

interface UIActions {
setMode: (mode: 'agent' | 'ide') => void;
setView: (view: UIState['view']) => void;
toggleSidebar: () => void;
setSidebarWidth: (w: number) => void;
setRightPanelWidth: (w: number) => void;
setBottomPanelHeight: (h: number) => void;
setIdeSidebarView: (view: UIState['ideSidebarView']) => void;
setTheme: (theme: UIState['theme']) => void;
}

export const useUIStore = create<UIState & UIActions>()(
persist(
immer((set) => ({
mode: 'agent',
view: 'agent',
sidebarCollapsed: false,
sidebarWidth: 220,
rightPanelWidth: 320,
bottomPanelHeight: 200,
ideSidebarView: 'explorer',
theme: 'dark',

setMode: (mode) =>
set((s) => {
s.mode = mode;
}),
setView: (view) =>
set((s) => {
s.view = view;
Expand All @@ -61,10 +51,6 @@ export const useUIStore = create<UIState & UIActions>()(
set((s) => {
s.bottomPanelHeight = h;
}),
setIdeSidebarView: (view) =>
set((s) => {
s.ideSidebarView = view;
}),
setTheme: (theme) =>
set((s) => {
s.theme = theme;
Expand Down
17 changes: 17 additions & 0 deletions packages/desktop/test/app-agent-layout-inline.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { describe, expect, it } from 'vitest';
import { existsSync, readFileSync } from 'fs';
import { resolve } from 'path';

const srcRoot = resolve(__dirname, '..', 'src');
const appSource = readFileSync(resolve(srcRoot, 'App.tsx'), 'utf8');

describe('App agent layout', () => {
it('owns the agent view routing after removing AgentLayout', () => {
expect(existsSync(resolve(srcRoot, 'layouts', 'AgentLayout.tsx'))).toBe(false);
expect(appSource).not.toContain('AgentLayout');
expect(appSource).toContain('useAgentCore()');
expect(appSource).toContain('<ProjectStrip />');
expect(appSource).toContain('<AgentSidebar />');
expect(appSource).toContain('<AgentWorkspace sendMessage={sendMessage} abort={abort} />');
});
});
Loading