feat: remove legacy OpenCode runtime

Cut product flows over to Coding/Pi and retain only the migration-owned v1 boundary. Promote supported native optional packages because electron-builder omitted pnpm transitive optional closure from the packaged ASAR.
This commit is contained in:
2026-08-24 12:17:43 +08:00
parent 61fede2b4d
commit 5a275b93a7
199 changed files with 1330 additions and 64725 deletions

View File

@@ -9,7 +9,7 @@ import { Sidebar } from './Sidebar';
import { TitleBar } from './TitleBar';
import { Button } from '@/components/ui/button';
import { getAiModuleForPath } from '@/lib/ai-modules';
import { useOpencodeStore } from '@/stores/opencode';
import { useCodingWorkspaceStore } from '@/stores/coding-workspace';
import { useProjectConfigStore } from '@/stores/project-config';
import { useSettingsStore } from '@/stores/settings';
import { cn } from '@/lib/utils';
@@ -18,7 +18,7 @@ import type { SidebarPeekSource } from './sidebar-peek';
const SIDEBAR_PEEK_CLOSE_DELAY_MS = 180;
export function MainLayout() {
const activeProject = useOpencodeStore((state) => state.activeProject);
const activeProject = useCodingWorkspaceStore((state) => state.activeProject);
const sidebarCollapsed = useSettingsStore((state) => state.sidebarCollapsed);
const config = useProjectConfigStore((state) => activeProject ? state.configsByProjectId[activeProject.id] : undefined);
const load = useProjectConfigStore((state) => state.load);
@@ -36,7 +36,7 @@ export function MainLayout() {
const isProgrammingModule = activeModule === 'programming';
const isPaintingModule = activeModule === 'painting';
const isPromptMuseum = location.pathname === '/image-prompts' || location.pathname.startsWith('/image-prompts/');
const isChatWorkspace = location.pathname === '/opencode-chat';
const isChatWorkspace = location.pathname === '/chat';
const isInitializationSafeRoute = location.pathname === '/project-config' || !isProgrammingModule;
const handleSidebarPeekChange = useCallback((open: boolean, source: SidebarPeekSource) => {

View File

@@ -46,9 +46,9 @@ import { getAccountInitial } from '@/components/profile/user-avatar-utils';
import { UserProfileDialog } from '@/components/profile/UserProfileDialog';
import { useSettingsStore } from '@/stores/settings';
import { useAuthStore, type AuthUser } from '@/stores/auth';
import { useOpencodeStore, type ProjectDirectoryMode } from '@/stores/opencode';
import { useCodingWorkspaceStore } from '@/stores/coding-workspace';
import { useProviderStore } from '@/stores/providers';
import type { OpencodeProject } from '@/types/opencode';
import type { CodingProjectSummary } from '@/types/coding-project';
import { useProjectConfigStore } from '@/stores/project-config';
import type { ProjectType } from '../../../shared/project-config';
import { toast } from 'sonner';
@@ -65,10 +65,12 @@ type TokenUsageState = {
};
type ProjectEntryError = {
project: OpencodeProject;
project: CodingProjectSummary;
message: string;
};
type ProjectDirectoryMode = 'use-selected-directory' | 'create-child-directory';
function getFolderName(pathValue: string): string {
const trimmed = pathValue.trim();
const withoutTrailingSeparators = trimmed.replace(/[\\/]+$/u, '');
@@ -133,13 +135,12 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi
const { t } = useTranslation('common');
const sidebarPinnedCollapsed = useSettingsStore((state) => state.sidebarCollapsed);
const sidebarCollapsed = sidebarPinnedCollapsed && !sidebarPeekOpen;
const opencodeProjects = useOpencodeStore((state) => state.projects);
const activeProject = useOpencodeStore((state) => state.activeProject);
const loadProjectList = useOpencodeStore((state) => state.loadProjectList);
const activateProjectLocally = useOpencodeStore((state) => state.activateProjectLocally);
const setActiveProject = useOpencodeStore((state) => state.setActiveProject);
const removeProject = useOpencodeStore((state) => state.removeProject);
const createProject = useOpencodeStore((state) => state.createProject);
const projects = useCodingWorkspaceStore((state) => state.projects);
const activeProject = useCodingWorkspaceStore((state) => state.activeProject);
const loadProjectList = useCodingWorkspaceStore((state) => state.load);
const setActiveProject = useCodingWorkspaceStore((state) => state.setActiveProject);
const removeProject = useCodingWorkspaceStore((state) => state.removeProject);
const createProject = useCodingWorkspaceStore((state) => state.createProject);
const projectConfigs = useProjectConfigStore((state) => state.configsByProjectId);
const loadProjectConfig = useProjectConfigStore((state) => state.load);
const removeProjectConfig = useProjectConfigStore((state) => state.remove);
@@ -166,7 +167,7 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi
const [createProjectError, setCreateProjectError] = useState<string | null>(null);
const [creatingProject, setCreatingProject] = useState(false);
const [projectEntryError, setProjectEntryError] = useState<ProjectEntryError | null>(null);
const [removeProjectCandidate, setRemoveProjectCandidate] = useState<OpencodeProject | null>(null);
const [removeProjectCandidate, setRemoveProjectCandidate] = useState<CodingProjectSummary | null>(null);
const [robotOverview, setRobotOverview] = useState<AiHardwareOverview | null>(null);
const [robotOverviewLoading, setRobotOverviewLoading] = useState(false);
const [robotSelectedAgentId, setRobotSelectedAgentId] = useState<string | null>(() => readAiHardwareAgentId());
@@ -182,7 +183,7 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi
const isRobotModule = activeModule === 'robot';
const isPromptMuseum = location.pathname === '/image-prompts' || location.pathname.startsWith('/image-prompts/');
const projectConfigPath = '/project-config';
const visibleProjects = opencodeProjects;
const visibleProjects = projects;
const selectedProjectFolderName = getFolderName(newProjectSelectedPath);
const accountName = userProfile?.displayName?.trim() || getAuthUserDisplayName(authUser) || '未登录用户';
const accountFullName = accountName;
@@ -416,24 +417,23 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi
setCreateProjectError(null);
};
const showProjectEntryError = (project: OpencodeProject, message: string) => {
const showProjectEntryError = (project: CodingProjectSummary, message: string) => {
setProjectEntryError({ project, message });
};
const enterProject = async (project: OpencodeProject) => {
const enterProject = async (project: CodingProjectSummary) => {
const result = await loadProjectConfig(project.id);
if (result.status !== 'valid' || !result.config) {
showProjectEntryError(project, result.status === 'missing' ? '项目缺少 .niancode/project.json' : result.error ?? '项目配置无效');
return;
}
activateProjectLocally(project);
await setActiveProject(project.id);
navigate(result.config.initialized
? '/opencode-chat'
? '/chat'
: projectConfigPath);
void setActiveProject(project.id).catch(() => undefined);
};
const readAndEnterProject = async (project: OpencodeProject) => {
const readAndEnterProject = async (project: CodingProjectSummary) => {
setProjectEntryError(null);
try {
await enterProject(project);
@@ -459,10 +459,10 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi
setCreateProjectError(null);
try {
const project = await createProject({
directoryMode: newProjectDirectoryMode,
selectedPath,
projectType: newProjectType,
...(newProjectDirectoryMode === 'create-child-directory' ? { projectName } : {}),
...(newProjectDirectoryMode === 'create-child-directory'
? { parentPath: selectedPath, projectName }
: { projectPath: selectedPath }),
});
setCreateDialogOpen(false);
await enterProject(project);
@@ -473,7 +473,7 @@ export function Sidebar({ workspaceLayout = false, sidebarPeekOpen = false, onSi
}
};
const openProject = async (project: OpencodeProject) => {
const openProject = async (project: CodingProjectSummary) => {
await readAndEnterProject(project);
};

View File

@@ -10,8 +10,8 @@ import { createPortal } from 'react-dom';
import { Copy, FolderOpen, Minus, PanelLeft, PanelLeftClose, Square, X } from 'lucide-react';
import { invokeIpc } from '@/lib/api-client';
import { cn } from '@/lib/utils';
import { useCodingWorkspaceStore } from '@/stores/coding-workspace';
import { useSettingsStore } from '@/stores/settings';
import { useOpencodeStore } from '@/stores/opencode';
import logoWordmarkSource from '@/assets/makelore-wordmark-source.png';
import type { SidebarPeekSource } from './sidebar-peek';
@@ -61,7 +61,7 @@ function ProductTitleBar({
onSidebarPeekChange?: SidebarPeekChange;
}) {
const sidebarCollapsed = useSettingsStore((state) => state.sidebarCollapsed);
const activeProject = useOpencodeStore((state) => state.activeProject);
const activeProject = useCodingWorkspaceStore((state) => state.activeProject);
const toolbarButtonClass = 'no-drag motion-press flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-surface-subtle hover:text-foreground';
const setSidebarCollapsed = useSettingsStore((state) => state.setSidebarCollapsed);
const toggleSidebar = () => setSidebarCollapsed(!sidebarCollapsed);