Merge remote-tracking branch 'origin/main' into HEAD

# Conflicts:
#	server/index.js
This commit is contained in:
Simos Mikelatos
2026-06-29 07:43:33 +00:00
139 changed files with 15972 additions and 690 deletions

View File

@@ -66,6 +66,7 @@ export type MainContentHeaderProps = {
selectedSession: ProjectSession | null;
shouldShowTasksTab: boolean;
shouldShowBrowserTab: boolean;
shouldShowComputerTab: boolean;
isMobile: boolean;
onMenuClick: () => void;
};

View File

@@ -6,11 +6,14 @@ import StandaloneShell from '../../standalone-shell/view/StandaloneShell';
import GitPanel from '../../git-panel/view/GitPanel';
import PluginTabContent from '../../plugins/view/PluginTabContent';
import { BrowserUsePanel } from '../../browser-use';
import { ComputerUsePanel } from '../../computer-use';
import type { MainContentProps } from '../types/types';
import { useTaskMaster } from '../../../contexts/TaskMasterContext';
import { usePaletteOpsRegister } from '../../../contexts/PaletteOpsContext';
import { useTasksSettings } from '../../../contexts/TasksSettingsContext';
import { useUiPreferences } from '../../../hooks/useUiPreferences';
import { useFileOpenResolver } from '../../../hooks/useFileOpenResolver';
import { COMPUTER_USE_MENUS_ENABLED } from '../../../constants/featureFlags';
import { authenticatedFetch } from '../../../utils/api';
import { useEditorSidebar } from '../../code-editor/hooks/useEditorSidebar';
import EditorSidebar from '../../code-editor/view/EditorSidebar';
@@ -58,9 +61,11 @@ function MainContent({
const { currentProject, setCurrentProject } = useTaskMaster() as TaskMasterContextValue;
const { tasksEnabled, isTaskMasterInstalled } = useTasksSettings() as TasksSettingsContextValue;
const [browserUseEnabled, setBrowserUseEnabled] = useState(false);
const [computerUseEnabled, setComputerUseEnabled] = useState<boolean | undefined>(undefined);
const shouldShowTasksTab = Boolean(tasksEnabled && isTaskMasterInstalled);
const shouldShowBrowserTab = browserUseEnabled;
const shouldShowComputerTab = COMPUTER_USE_MENUS_ENABLED && computerUseEnabled === true;
const {
editingFile,
@@ -77,6 +82,10 @@ function MainContent({
isMobile,
});
// Resolves bare/partial file references (e.g. links inside chat messages) to
// real project files before opening them in the in-app editor.
const resolvedFileOpen = useFileOpenResolver(selectedProject, handleFileOpen);
useEffect(() => {
// Identify projects by DB `projectId`; the TaskMaster context uses the
// same identifier to key its internal maps.
@@ -116,11 +125,69 @@ function MainContent({
}
}, [shouldShowBrowserTab, activeTab, setActiveTab]);
const loadComputerUseSettings = useCallback(async () => {
try {
const [settingsResponse, statusResponse] = await Promise.allSettled([
authenticatedFetch('/api/computer-use/settings'),
authenticatedFetch('/api/computer-use/status'),
]);
const settingsRes = settingsResponse.status === 'fulfilled' ? settingsResponse.value : null;
const statusRes = statusResponse.status === 'fulfilled' ? statusResponse.value : null;
const readJson = async (response: Response | null) => {
if (!response) return null;
try {
return await response.json();
} catch {
return null;
}
};
const settingsData = await readJson(settingsRes);
const statusData = await readJson(statusRes);
const runtime = statusData?.data?.runtime;
const settingsUsable = Boolean(settingsRes?.ok && settingsData?.success !== false);
const statusUsable = Boolean(statusRes?.ok && statusData?.success !== false);
const settingsEnabled = Boolean(
settingsUsable &&
settingsData?.data?.settings?.enabled
);
const cloudEnabled = Boolean(
statusUsable &&
runtime === 'cloud' &&
statusData?.data?.enabled
);
if (runtime === 'cloud') {
setComputerUseEnabled(cloudEnabled);
} else if (settingsUsable) {
setComputerUseEnabled(settingsEnabled);
} else if (statusUsable) {
setComputerUseEnabled(Boolean(statusData?.data?.enabled));
}
} catch {
// Keep the current tab availability on transient status/settings failures.
}
}, []);
useEffect(() => {
void loadComputerUseSettings();
window.addEventListener('computerUseSettingsChanged', loadComputerUseSettings);
return () => window.removeEventListener('computerUseSettingsChanged', loadComputerUseSettings);
}, [loadComputerUseSettings]);
useEffect(() => {
if (!shouldShowComputerTab && activeTab === 'computer') {
setActiveTab('chat');
}
}, [shouldShowComputerTab, activeTab, setActiveTab]);
usePaletteOpsRegister({
openFile: (filePath: string) => {
setActiveTab('files');
handleFileOpen(filePath);
},
// Opens the editor side panel in place, keeping the current tab (e.g. chat).
openFileInEditor: (filePath: string) => {
resolvedFileOpen(filePath);
},
});
if (isLoading) {
@@ -140,6 +207,7 @@ function MainContent({
selectedSession={selectedSession}
shouldShowTasksTab={shouldShowTasksTab}
shouldShowBrowserTab={shouldShowBrowserTab}
shouldShowComputerTab={shouldShowComputerTab}
isMobile={isMobile}
onMenuClick={onMenuClick}
/>
@@ -208,6 +276,12 @@ function MainContent({
</div>
)}
{shouldShowComputerTab && activeTab === 'computer' && (
<div className="h-full overflow-hidden">
<ComputerUsePanel isVisible={activeTab === 'computer'} onShowSettings={onShowSettings} />
</div>
)}
{activeTab.startsWith('plugin:') && (
<div className="h-full overflow-hidden">
<PluginTabContent

View File

@@ -11,6 +11,7 @@ export default function MainContentHeader({
selectedSession,
shouldShowTasksTab,
shouldShowBrowserTab,
shouldShowComputerTab,
isMobile,
onMenuClick,
}: MainContentHeaderProps) {
@@ -61,6 +62,7 @@ export default function MainContentHeader({
setActiveTab={setActiveTab}
shouldShowTasksTab={shouldShowTasksTab}
shouldShowBrowserTab={shouldShowBrowserTab}
shouldShowComputerTab={shouldShowComputerTab}
/>
</div>
{canScrollRight && (

View File

@@ -1,4 +1,4 @@
import { MessageSquare, Terminal, Folder, GitBranch, ClipboardCheck, MonitorPlay, type LucideIcon } from 'lucide-react';
import { MessageSquare, Terminal, Folder, GitBranch, ClipboardCheck, MonitorCog, MonitorPlay, type LucideIcon } from 'lucide-react';
import type { Dispatch, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next';
@@ -12,6 +12,7 @@ type MainContentTabSwitcherProps = {
setActiveTab: Dispatch<SetStateAction<AppTab>>;
shouldShowTasksTab: boolean;
shouldShowBrowserTab: boolean;
shouldShowComputerTab: boolean;
};
type BuiltInTab = {
@@ -45,6 +46,13 @@ const BROWSER_TAB: BuiltInTab = {
icon: MonitorPlay,
};
const COMPUTER_TAB: BuiltInTab = {
kind: 'builtin',
id: 'computer',
labelKey: 'tabs.computer',
icon: MonitorCog,
};
const TASKS_TAB: BuiltInTab = {
kind: 'builtin',
id: 'tasks',
@@ -57,6 +65,7 @@ export default function MainContentTabSwitcher({
setActiveTab,
shouldShowTasksTab,
shouldShowBrowserTab,
shouldShowComputerTab,
}: MainContentTabSwitcherProps) {
const { t } = useTranslation();
const { plugins } = usePlugins();
@@ -64,6 +73,7 @@ export default function MainContentTabSwitcher({
const builtInTabs: BuiltInTab[] = [
...BASE_TABS,
...(shouldShowBrowserTab ? [BROWSER_TAB] : []),
...(shouldShowComputerTab ? [COMPUTER_TAB] : []),
...(shouldShowTasksTab ? [TASKS_TAB] : []),
];

View File

@@ -29,7 +29,11 @@ function getTabTitle(activeTab: AppTab, shouldShowTasksTab: boolean, t: (key: st
}
if (activeTab === 'browser') {
return 'Browser';
return t('tabs.browser');
}
if (activeTab === 'computer') {
return t('tabs.computer');
}
return 'Project';