Merge file preview into a Work/Files third column and rework the left rail

Why: The three-column workbench redesign converges entries and hierarchy:
project switching tops the left rail (identity shown once), sessions and
search stay centered, files/workspaces/account sink to the bottom. The
right column becomes a Work/Files third column that absorbs the preview
pane, which is no longer an independent fourth region; the artifacts
workspace overlay folds into the Files entry, and stop control
consolidates into the input area with a light fast/slow-lane status hint.

Evidence: make test-frontend NOT_RUN at commit time; the run and its
outcome are recorded in the Dev task card before integration.

Impact: App.tsx layout and divider width tiers (work 280-560, files with
open preview 420-1100); store UI state rightTab work/files plus filesView
with syncFilesEntry replacing syncPreviewRail; Workbench dual entry;
PreviewPane gains a back-to-list control; TaskSidebar project switcher;
TopBar drops project identity; Conversation drops the header stop button
and gains the input status line; workspaces.ts drops the artifacts builtin.

Refs: three-column workbench proposal (2026-10-11), DESIGN.md 6/9.3
revision follows in the Dev repo.
This commit is contained in:
2026-10-11 02:40:18 +00:00
parent 339a9ebc2d
commit 204ca67dc7
11 changed files with 195 additions and 121 deletions
+2 -3
View File
@@ -1,5 +1,6 @@
// 体系工具排位:服务端声明的工作区对所有用户可见,按 shortcut 数字占位;
// 内置「工件」「代理」补进空位。插件管理面板不进这条清单。
// 内置「代理」补进空位。文件浏览在第三栏「文件」入口(方案:入口收敛),不再占体系工具位。
// 插件管理面板不进这条清单。
export interface WorkspaceEntry {
key: string
@@ -16,7 +17,6 @@ export interface WorkspaceSource {
}
const BUILTINS: Omit<WorkspaceEntry, 'shortcut'>[] = [
{ key: 'artifacts', title: '工件', icon: '📦' },
{ key: 'agents', title: '代理', icon: '🤖' },
]
@@ -56,7 +56,6 @@ export function buildWorkspaceEntries(server: WorkspaceSource[]): WorkspaceEntry
return 99
}
ranked.push({ rank: takeFree(1), entry: BUILTINS[0] })
ranked.push({ rank: takeFree(2), entry: BUILTINS[1] })
for (const entry of unranked) ranked.push({ rank: takeFree(9), entry })
return ranked
.filter(item => item.rank <= 9)