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
4 changes: 0 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,3 @@ STUB_API_KEY=
# Vite dev server port for Electron renderer process
# Default: 4927. Auto-increments when creating new worktrees to avoid port conflicts
VITE_DEV_SERVER_PORT=4927

# Enable new UI layout (workspace tabs at top, worktree sidebar)
# Set to 'true' to enable the new mock UI for visual iteration
ENABLE_NEW_UI=false
3 changes: 0 additions & 3 deletions apps/desktop/electron.vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ export default defineConfig({
define: {
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
"process.platform": JSON.stringify(process.platform),
"import.meta.env.ENABLE_NEW_UI": JSON.stringify(
process.env.ENABLE_NEW_UI || "false",
),
"import.meta.env.DEV_SERVER_PORT": JSON.stringify(getPortSync()),
},

Expand Down
26 changes: 6 additions & 20 deletions apps/desktop/src/main/lib/tmux-manager.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { spawnSync } from "node:child_process";
import { randomUUID } from "node:crypto";
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { mkdir } from "node:fs/promises";
import os from "node:os";
import { dirname, join } from "node:path";
import { spawnSync } from "node:child_process";
import type { BrowserWindow } from "electron";
import { app } from "electron";
import * as pty from "node-pty";
Expand Down Expand Up @@ -231,7 +231,9 @@ class TmuxManager {

// Resize the tmux window BEFORE attaching to ensure proper dimensions
// This is crucial for reconnection after restart
console.log(`[TmuxManager] Resizing tmux window ${sid} to ${cols}x${rows} before attach`);
console.log(
`[TmuxManager] Resizing tmux window ${sid} to ${cols}x${rows} before attach`,
);
const resizeResult = spawnSync("tmux", [
"-L",
this.TMUX_SOCKET,
Expand All @@ -253,13 +255,7 @@ class TmuxManager {

// Force tmux to refresh and reflow content at new size
// This ensures the pane content is properly wrapped for the new dimensions
spawnSync("tmux", [
"-L",
this.TMUX_SOCKET,
"refresh-client",
"-t",
sid,
]);
spawnSync("tmux", ["-L", this.TMUX_SOCKET, "refresh-client", "-t", sid]);

// Attach to the session via node-pty
console.log(`[TmuxManager] Attaching to session: ${sid}`);
Expand Down Expand Up @@ -289,10 +285,6 @@ class TmuxManager {

// Set up data listener
ptyProcess.onData((data: string) => {
// Debug: log what's coming from PTY
if (data.includes("1;2c") || data.includes("0;276")) {
console.log(`[TmuxManager] PTY output from ${sid}:`, JSON.stringify(data), `(length: ${data.length})`);
}
this.addTerminalMessage(sid, data);
});

Expand Down Expand Up @@ -445,7 +437,6 @@ class TmuxManager {
const session = this.sessions.get(sid);
if (session?.pty) {
// Debug: log what's being written
console.log(`[TmuxManager] Writing to ${sid}:`, JSON.stringify(data), `(length: ${data.length})`);
session.pty.write(data);
return true;
}
Expand Down Expand Up @@ -561,11 +552,8 @@ class TmuxManager {

// Return in-memory history if available
if (session.outputHistory.length > 0) {
console.log(`[TmuxManager] Returning ${session.outputHistory.length} bytes of cached history for ${sid}`);
return session.outputHistory;
}

console.log(`[TmuxManager] No cached history for ${sid}, tmux will send content on attach`);
return undefined;
}

Expand Down Expand Up @@ -631,9 +619,7 @@ class TmuxManager {
"utf-8",
);

console.log(
`[TmuxManager] Saved ${metadata.length} sessions to disk`,
);
console.log(`[TmuxManager] Saved ${metadata.length} sessions to disk`);
} catch (error) {
console.error("[TmuxManager] Failed to save sessions to disk:", error);
}
Expand Down
32 changes: 11 additions & 21 deletions apps/desktop/src/renderer/screens/main/MainScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,8 @@ function DroppableMainContent({
return (
<div
ref={setNodeRef}
className={`flex-1 overflow-hidden m-1 rounded-lg relative ${
isOver ? "ring-2 ring-blue-500 ring-inset" : ""
}`}
className={`flex-1 overflow-hidden m-1 rounded-lg relative ${isOver ? "ring-2 ring-blue-500 ring-inset" : ""
}`}
>
{children}
{isOver && (
Expand All @@ -70,14 +69,11 @@ function DroppableMainContent({
}

export function MainScreen() {
// Check if new UI is enabled
const enableNewUI = import.meta.env.ENABLE_NEW_UI === "true";

// If new UI is enabled, render the new layout
if (enableNewUI) {
return <NewLayoutMain />;
}
// Use the new layout by default
return <NewLayoutMain />;
}

export function OldMainScreen() {
// Otherwise, render the original layout
const [isSidebarOpen, setIsSidebarOpen] = useState(true);
const [showSidebarOverlay, setShowSidebarOverlay] = useState(false);
Expand Down Expand Up @@ -1687,18 +1683,16 @@ export function MainScreen() {
)}

{/* Sidebar overlay when hidden and hovering */}
{!isSidebarOpen && showSidebarOverlay && workspaces && (
{!isSidebarOpen && showSidebarOverlay && currentWorkspace && (
<div
className="fixed left-0 top-0 bottom-0 w-80 z-40 animate-in slide-in-from-left duration-200"
onMouseLeave={() => setShowSidebarOverlay(false)}
>
<div className="h-full border-r border-neutral-800 bg-neutral-950/95 backdrop-blur-sm">
<Sidebar
workspaces={workspaces}
currentWorkspace={currentWorkspace}
onTabSelect={handleTabSelect}
onWorktreeCreated={handleWorktreeCreated}
onWorkspaceSelect={handleWorkspaceSelect}
onUpdateWorktree={handleUpdateWorktree}
selectedTabId={selectedTabId ?? undefined}
onCollapse={() => {
Expand All @@ -1723,13 +1717,11 @@ export function MainScreen() {
onCollapse={() => setIsSidebarOpen(false)}
onExpand={() => setIsSidebarOpen(true)}
>
{isSidebarOpen && workspaces && (
{isSidebarOpen && currentWorkspace && (
<Sidebar
workspaces={workspaces}
currentWorkspace={currentWorkspace}
onTabSelect={handleTabSelect}
onWorktreeCreated={handleWorktreeCreated}
onWorkspaceSelect={handleWorkspaceSelect}
onUpdateWorktree={handleUpdateWorktree}
selectedTabId={selectedTabId ?? undefined}
onCollapse={() => {
Expand All @@ -1756,16 +1748,14 @@ export function MainScreen() {
panel.expand();
}
}}
workspaceName={currentWorkspace?.name}
currentBranch={currentWorkspace?.branch}
/>

{/* Content Area */}
<DroppableMainContent isOver={isOverMainContent}>
{showDiffView &&
diffWorktreeId &&
diffWorktree &&
currentWorkspace ? (
diffWorktreeId &&
diffWorktree &&
currentWorkspace ? (
// Show diff view
<div className="w-full h-full">
<DiffTab
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface TabContentProps {
onTabFocus: (tabId: string) => void;
workspaceName?: string;
mainBranch?: string;
isVisibleInMosaic?: boolean; // Whether this tab is visible in a mosaic layout
}

/**
Expand All @@ -39,6 +40,7 @@ export default function TabContent({
onTabFocus,
workspaceName,
mainBranch,
isVisibleInMosaic = false,
}: TabContentProps) {
const handleFocus = () => {
onTabFocus(tab.id);
Expand Down Expand Up @@ -71,6 +73,7 @@ export default function TabContent({
groupTabId={groupTabId}
selectedTabId={selectedTabId}
onFocus={handleFocus}
isVisibleInMosaic={isVisibleInMosaic}
/>
);

Expand Down Expand Up @@ -165,6 +168,7 @@ interface TerminalTabContentProps {
groupTabId: string; // ID of the parent group tab
selectedTabId?: string; // Currently selected tab ID
onFocus: () => void;
isVisibleInMosaic?: boolean; // Whether this tab is visible in a mosaic layout
}

function TerminalTabContent({
Expand All @@ -175,10 +179,13 @@ function TerminalTabContent({
groupTabId,
selectedTabId,
onFocus,
isVisibleInMosaic = false,
}: TerminalTabContentProps) {
const terminalId = tab.id;
const terminalCreatedRef = useRef(false);
const isSelected = selectedTabId === tab.id;
// Terminal should be visible if it's either selected OR visible in a mosaic layout
const isVisible = isSelected || isVisibleInMosaic;

// Terminal creation and lifecycle
// NOTE: Actual terminal-create is now deferred to the Terminal component
Expand Down Expand Up @@ -234,7 +241,7 @@ function TerminalTabContent({
<Terminal
key={terminalId}
terminalId={terminalId}
hidden={!isSelected}
hidden={!isVisible}
onFocus={onFocus}
cwd={terminalCwd}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ export default function TabGroup({
onTabFocus={onTabFocus}
workspaceName={workspaceName}
mainBranch={mainBranch}
isVisibleInMosaic={true}
/>
</div>
</MosaicWindow>
Expand Down Expand Up @@ -259,16 +260,20 @@ export default function TabGroup({
.mosaic-theme-dark .mosaic-window {
background: #1a1a1a;
border: 1px solid #333;
outline: none;
transition: outline 0.15s ease;
}
.mosaic-theme-dark .mosaic-window .mosaic-window-toolbar {
background: #262626;
border-bottom: 1px solid #333;
height: 32px;
padding: 0 8px;
transition: background-color 0.15s ease;
}
.mosaic-theme-dark .mosaic-window .mosaic-window-title {
color: #e5e5e5;
font-size: 12px;
transition: color 0.15s ease;
}
.mosaic-theme-dark .mosaic-window-body {
background: #1a1a1a;
Expand All @@ -279,9 +284,8 @@ export default function TabGroup({
.mosaic-theme-dark .mosaic-split:hover {
background: #444;
}
.active-mosaic-window .mosaic-window {
border: 1px solid #3b82f6 !important;
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.3);
.active-mosaic-window .mosaic-window-toolbar {
background: #3a3a3a !important;
}
`}</style>
</div>
Expand Down
Loading
Loading