style(workspace): remove the embedded work preview title bar

This commit is contained in:
鲨鱼辣椒
2026-09-28 16:09:52 +08:00
parent d284287741
commit 064096edbd
5 changed files with 26 additions and 6 deletions

View File

@@ -8,7 +8,7 @@
- Worktree: /Users/chillishark/Makelore 麦洛/.codex-worktrees/makelore-teacher-reply-cleanup
- Base commit: ae0f72d8fa0089f87b41d272da220e1c1397aec8
- Owner: codex
- Status: Ready for Integration
- Status: In progress
## Scope
@@ -127,3 +127,12 @@
- Refreshed existing trial Renderer from committed 784fa8c to `index-DLBsnWbW.js`. Main PID 36109 and profile retained. Final DOM confirms visible composer hint text “继续看看👀” with `rgb(255, 242, 201)` background; captured and inspected the actual empty-composer screenshot `visible-hint-preview.png` in the local trial root. Login/account/project/draft/input/route checks passed; no generated conversation content or requests were inserted for demonstration.
- Window/panel/selection state changed during the live verification: the consultation panel was closed at snapshot and open at final capture, and the selection equality check was false. Preserved current interaction without a second forced selection restore; do not claim exact conversation/window state remained unchanged. The foreground monitor already observed the trial as its sole foreground application; refresh invoked no show/focus calls. Final capture was taken with the window unfocused.
- Temporary backup memory and inspector removed; local launch/build metadata updated. No cloud publication, Main restart, main merge or push. Final documentation drift has only the previously recorded unchanged imported task document diagnostic.
## Embedded Work Preview Header Follow-up
- User requests removal of the pictured horizontal “作品预览” title/icon/close row. Continue the current temporary workspace preview without taking desktop focus.
- Same feature ownership resumed and verified. Reused unchanged previously loaded project context; reread own task/entry and newly active welcome/truncation/role-review task records. Existing peer scopes remain unchanged; no work-preview overlap or unresolved product decision. Gate Passed. This scoped presentation change preserves the shared browser's lifecycle, navigation, recovery, native viewport and separate developer-browser UI.
- Plan: hide the redundant header only in embedded work preview, retain an accessible aside name and the existing top-level operation/work tabs; keep address navigation and standalone browser close controls. Update existing unit/native E2E assertions, compile, and refresh only the temporary Renderer. Main/remote branches and installed production application remain unchanged.
- Implemented conditional removal of the entire embedded title row (globe icon, “作品预览”, close button); the work-preview aside remains accessibly named. Address/back/forward/reload controls and the native viewport remain, while the standalone developer-browser header and close action are unchanged.
- Passed: 44 AgentBrowserPanel/CodingChatPanel unit tests, typecheck, full lint plus scoped test lint, full production compile and whitespace check. Updated shared Electron work-tab assertions without launching a native test instance.

View File

@@ -154,7 +154,7 @@ Pi 正式包必须继续运行 `pnpm run verify:artifact:pi`、`pnpm run smoke:p
- 首次发送会立即生成稳定的乐观用户消息;HTTP 202 只表示本地 Agent 已接收。后续失败不会删除已接受消息,不确定交付不会自动重发;准备失败可在目标 Conversation 上手动恢复。
- 运行中的 Conversation 可把新消息作为 steer 引导当前回答或 follow-up 排到下一轮,并显示队列位置;队列正常在 `agent_settled` 后释放,用户可中止当前运行。若 Pi 已终结但该握手丢失,Main 会在 30 秒宽限后仅探测目标线程:权威 idle 状态会补齐持久化最终回复并 exactly-once 释放 ownership,矛盾状态则显式失败该目标,且不会重放已接受请求。select/confirm/input/editor 交互在输入区上方回答,select 除预设选项外支持自由输入;交互提交或取消后立即从输入区移除,失效请求会就地提示并允许重试或取消。
- 隐藏 Conversation 的红色新消息标记只在出现新的待回答交互,或当前任务进入 completed、failed、aborted 终态时设置;助手流式文字、思考、工具过程和单个工具失败不会提前触发红点。
- 核心聊天页左侧显示品牌、项目及其对话;标题栏显示项目与当前 Conversation,并在右上角提供统一智能体入口和必要的中止/恢复按钮。中央“操作对话/作品”切换真实对话与项目浏览器预览,切换时保留操作草稿。点击智能体头像或主动气泡中的聊天入口,会同时打开智能体咨询并默认切到“作品”;仍可手动切回操作对话,单纯收到智能体气泡不会切换页面。点击“作品”会由 Main 检查已知本地页面:可访问则直接复用,否则向编程 Agent 发送固定的内部打开作品指令,检查现有服务、按项目实际脚本启动并调用 `agent_browser` 展示。当前项目正在制作时先等待;同一启动过程防止重复派发。失败时提供明确恢复入口:登录失效可“登录并继续”,返回相同账号和项目后接着打开;作品未打开可“帮我检查并打开”;普通操作中断可“帮我继续”,先核对已有进度再继续,保留当前输入草稿。仅对连接检查做两次有上限的自动重连并复用请求身份,不自动重放结果不确定的操作。最新失败提供一个恢复入口,空错误不再显示“本次处理失败。”;作品成功打开后收起对应失败提示。后台休眠释放预览窗口后,Main 在本次应用会话内保留项目对应的已验证地址,包括从地址栏或 Agent 成功打开的页面;回到前台或收到关闭状态时自动检查并恢复仍可访问的作品,不重复调用 Agent,也不依赖模型登录。手动打开成功会覆盖旧的启动请求结果,但不关闭后续恢复检查。窗口显示时发生关闭竞态会自动重试两次;仍无法显示则提供“重新打开作品”,不向学生暴露“开发浏览器已关闭”等内部错误,也不无限停留在打开中。内部指令不消耗学生草稿,也不参与对话自动命名,时间线隐藏这条内部指令及“已点击打开作品”操作记录,保留真实的处理结果和错误。学生作品区不展示 Console/Network 调试栏,也不订阅这两个面板的调试事件;Agent 的后台调试能力保留。项目设置、归档和会话管理保留在左侧。从已持久化的 user 消息仍可“从这里创建新对话分支”,assistant 消息和未持久化消息不提供该动作;分支只创建新的 Conversation 历史,不表示文件回滚。Pi 的工具调用与浏览器附件继续在对应的对话过程节点中按需展开;分享、待办、全局运行时和 revert/unrevert 不属于该产品界面。
- 核心聊天页左侧显示品牌、项目及其对话;标题栏显示项目与当前 Conversation,并在右上角提供统一智能体入口和必要的中止/恢复按钮。中央“操作对话/作品”切换真实对话与项目浏览器预览,切换时保留操作草稿。作品区直接显示地址栏和页面,不再重复显示“作品预览”标题、图标及关闭横栏;通过上方“操作对话”标签切回对话。点击智能体头像或主动气泡中的聊天入口,会同时打开智能体咨询并默认切到“作品”;仍可手动切回操作对话,单纯收到智能体气泡不会切换页面。点击“作品”会由 Main 检查已知本地页面:可访问则直接复用,否则向编程 Agent 发送固定的内部打开作品指令,检查现有服务、按项目实际脚本启动并调用 `agent_browser` 展示。当前项目正在制作时先等待;同一启动过程防止重复派发。失败时提供明确恢复入口:登录失效可“登录并继续”,返回相同账号和项目后接着打开;作品未打开可“帮我检查并打开”;普通操作中断可“帮我继续”,先核对已有进度再继续,保留当前输入草稿。仅对连接检查做两次有上限的自动重连并复用请求身份,不自动重放结果不确定的操作。最新失败提供一个恢复入口,空错误不再显示“本次处理失败。”;作品成功打开后收起对应失败提示。后台休眠释放预览窗口后,Main 在本次应用会话内保留项目对应的已验证地址,包括从地址栏或 Agent 成功打开的页面;回到前台或收到关闭状态时自动检查并恢复仍可访问的作品,不重复调用 Agent,也不依赖模型登录。手动打开成功会覆盖旧的启动请求结果,但不关闭后续恢复检查。窗口显示时发生关闭竞态会自动重试两次;仍无法显示则提供“重新打开作品”,不向学生暴露“开发浏览器已关闭”等内部错误,也不无限停留在打开中。内部指令不消耗学生草稿,也不参与对话自动命名,时间线隐藏这条内部指令及“已点击打开作品”操作记录,保留真实的处理结果和错误。学生作品区不展示 Console/Network 调试栏,也不订阅这两个面板的调试事件;Agent 的后台调试能力保留。项目设置、归档和会话管理保留在左侧。从已持久化的 user 消息仍可“从这里创建新对话分支”,assistant 消息和未持久化消息不提供该动作;分支只创建新的 Conversation 历史,不表示文件回滚。Pi 的工具调用与浏览器附件继续在对应的对话过程节点中按需展开;分享、待办、全局运行时和 revert/unrevert 不属于该产品界面。
- 普通消息接收成功不显示额外的技术提示;准备、错误和排队状态仍正常反馈。发送状态按请求对应的运行结束收敛,保留期间输入的新草稿;恢复历史时优先以持久消息身份关联,避免相同文本串联到其他请求。

View File

@@ -480,23 +480,24 @@ export function AgentBrowserPanel({
ref={panelRef}
className={cn(embedded ? 'relative flex min-h-0 w-full min-w-0 flex-1 flex-col overflow-hidden bg-background' : 'relative flex w-[400px] min-w-[300px] max-w-[48vw] shrink-0 flex-col overflow-hidden border-l border-border/80 bg-background shadow-[-16px_0_32px_hsl(220_20%_16%_/_0.06)] max-[900px]:fixed max-[900px]:inset-y-10 max-[900px]:right-0 max-[900px]:z-40 max-[900px]:max-w-[min(92vw,420px)]')}
data-testid="agent-browser-panel"
aria-label={embedded ? '作品预览' : '开发浏览器'}
>
<div className="flex h-10 shrink-0 items-center gap-2 border-b border-border/70 px-2.5">
{!embedded && <div className="flex h-10 shrink-0 items-center gap-2 border-b border-border/70 px-2.5">
<span className="flex h-6 w-6 items-center justify-center rounded-md bg-brand-soft text-brand">
<Globe2 className="h-3.5 w-3.5" aria-hidden="true" />
</span>
<h2 className="min-w-0 flex-1 truncate text-xs font-semibold">{embedded ? '作品预览' : '开发浏览器'}</h2>
<h2 className="min-w-0 flex-1 truncate text-xs font-semibold">开发浏览器</h2>
<Button
type="button"
variant="ghost"
size="icon"
className="h-8 w-8 rounded-md text-muted-foreground"
aria-label={embedded ? '收起作品' : '关闭开发浏览器'}
aria-label="关闭开发浏览器"
onClick={() => onOpenChange(false)}
>
<X className="h-4 w-4" aria-hidden="true" />
</Button>
</div>
</div>}
<form className="flex h-10 shrink-0 items-center gap-1 border-b border-border/70 px-2" onSubmit={handleOpenAddress}>
<Button type="button" variant="ghost" size="icon" className="h-7 w-7 rounded-md" aria-label="后退" disabled={!snapshot?.canGoBack || busy} onClick={() => handleNavigate('back')}>

View File

@@ -2189,6 +2189,10 @@ test('work tab prepares the page automatically and keeps the student draft throu
await expect(page.getByText('正在打开你的作品…', { exact: true })).toBeVisible();
await electronApp.evaluate(() => { (globalThis as unknown as { __makelorePiFirstChatE2E: { workReady: boolean } }).__makelorePiFirstChatE2E.workReady = true; });
await expect(page.getByRole('textbox', { name: '网页地址' })).toHaveValue('http://127.0.0.1:4173/');
await expect(page.getByTestId('agent-browser-panel')).toHaveAccessibleName('作品预览');
await expect(page.getByRole('heading', { name: '作品预览', exact: true })).toHaveCount(0);
await expect(page.getByRole('button', { name: '收起作品', exact: true })).toHaveCount(0);
await expect(page.getByTestId('agent-browser-viewport')).toBeVisible();
await expect(page.getByText('正在打开你的作品…', { exact: true })).toHaveCount(0);
// A manual address open must not permanently disable recovery checks.
await page.getByRole('textbox', { name: '网页地址' }).fill('http://127.0.0.1:4173/');

View File

@@ -264,7 +264,13 @@ describe('AgentBrowserPanel', () => {
const onOpenChange = vi.fn();
const view = render(<AgentBrowserPanel projectId="project-a" open embedded onOpenChange={onOpenChange} />);
await waitFor(() => expect(latestPresentation()).toMatchObject({ project_id: 'project-a', visible: true }));
expect(screen.getByRole('complementary', { name: '作品预览' })).toBeVisible();
expect(screen.queryByRole('heading', { name: '作品预览' })).not.toBeInTheDocument();
expect(screen.queryByRole('button', { name: '收起作品' })).not.toBeInTheDocument();
expect(screen.getByRole('textbox', { name: '网页地址' })).toHaveValue('http://127.0.0.1:4173/');
expect(screen.getByRole('textbox', { name: '网页地址' })).toBeEnabled();
expect(screen.getByTestId('agent-browser-viewport')).toBeVisible();
expect(screen.getByTestId('agent-browser-viewport')).toHaveAccessibleName('作品画面');
view.rerender(<AgentBrowserPanel projectId="project-a" open={false} embedded onOpenChange={onOpenChange} />);
await waitFor(() => expect(latestPresentation()).toMatchObject({ visible: false }));