Compare commits

...
2 Commits
Author SHA1 Message Date
brother7 b0bf7a49eb docs: record Windows Code titlebar integration
Electron E2E / Electron E2E (macos-latest) (push) Has been cancelled
Electron E2E / Electron E2E (ubuntu-latest) (push) Has been cancelled
Electron E2E / Electron E2E (windows-latest) (push) Has been cancelled
2026-09-15 10:33:42 +08:00
brother7 dae64e52b9 fix: reserve Windows titlebar chrome space for Code actions 2026-09-15 10:14:44 +08:00
8 changed files with 191 additions and 7 deletions

No files matched your search

@@ -4,6 +4,8 @@ This file is the integrated default-branch snapshot. Feature tasks record progre
## Integrated Through
- 2026-09-15:任务 `20260915-merge-windows-titlebar-bde0505c` 经用户授权移交主目录登记,将修复源 `dae64e52b94f54c61b14d744ef6e6d0580af2d3a` 无冲突快进合入本地 `main`。Windows Code 对话标题栏按共用的 148 px 窗口按钮与 96 px Logo 尺寸限制可交互区域,浏览器、中止和恢复按钮保持在 Logo 左侧。产品树与已验证源一致,沿用 42 项相关单测、类型检查、scoped lint、Vite 全目标构建及 Electron 标题栏/Code 交互验证;覆盖最小 1024 px 窗口、125% 缩放和窗口最大化/还原。详见[源任务](tasks/20260915-windows-logo-overlap-5106511f.md)。原有三份未跟踪文档保持,源记录原样导入;未推送、打包或安装客户端。
- 2026-09-15:任务 `20260915-merge-platform-embedding-ml-4e78b319` 经用户授权移交主目录登记,将独立审查通过的 `c466039adb789368189e43971afe489d450d5c82` 无冲突快进合入本地 `main`。知识库 embedding 统一由 Yuxi 配置并直连供应商,平台承担费用,不计算用户用量、词元点数或金额预算;聊天计费保持。客户端知识模型列表沿用 id/name/dimension 契约,配置说明只指向 Yuxi,知识及预算页面明确平台承担向量化成本。 本次新规则取代早期知识库目录交集、one-api 向量接口和创建者付款说明,历史记录保留。源聚焦单测 22 passed、Electron E2E 1 passed、typecheck、scoped lint 与 Vite build 通过;最终文字调整后聚焦 22 单测再次通过,独立 Reviewer Standards/Spec PASS;详见[源任务](tasks/20260914-yuxi-embedding-ml-a174ed62.md)。原有三份文档保持,无新 SQL 或专用环境变量,未推送或部署;真实供应商及完整知识库拓扑验收另行执行。
- 2026-09-14:任务 `20260914-agent-ui-integration-4a838e7c` 将引导式智能体 UI 源 `6e6a8c92ddb66747a71af714809e2205292a0bf9` 无冲突合入本地 `main`,合并提交 `5a974cf78493b8dd92e176cc26fbe323a18e9570`。面向非专业用户与 8–15 岁学生的创建引导、基础要求、高级设置折叠、保存后重新试用、历史对比及首次自用确认已集成,见[已接受决策](../10-decisions/ADR-2026-09-11-personal-cloud-agents.md)。保留主分支连接时差修复,产品代码与已验证源一致;集成时补充两条异步状态测试等待。组合验证累计 89 项相关单测、类型检查、Vite 全目标构建、Electron 引导用例通过;全量测试沿用源记录中已确认的 Pi v6/v7 既有失败限制。原有三份未跟踪记录原样保留;已授权的源工作区清理因 Git 目录非空错误受阻,残余保留,分支和提交完整。未推送、打包或部署。详见[集成记录](tasks/20260914-agent-ui-integration-4a838e7c.md)。
@@ -0,0 +1,45 @@
# Task: Merge Windows Code titlebar logo fix
## Identity
- Task ID: 20260915-merge-windows-titlebar-bde0505c
- Mode: Integration
- Branch: main
- Worktree: D:\Datas\OthersProjects\makelore
- Base commit: a39fbc1619470ad8d47a1b9131b2cada5b940ec5
- Owner: codex
- Status: Ready for Integration
## Scope
- Integrate the completed Windows Code titlebar correction `dae64e52b94f54c61b14d744ef6e6d0580af2d3a` into local main and record its exact integrated frontier.
## Intent And Constraints
- The user explicitly requested merging to main, then approved handing over the previous main-worktree registration while preserving the three existing untracked task documents. Released only `20260915-merge-platform-embedding-ml-4e78b319` and claimed this integration task through the bundled scripts with `--adopt-existing`.
- Concurrent Task Gate passed: task identity, integration mode, main branch, absolute worktree and base match the official status record. The repository integration lock was acquired.
- Planning Gate passed after reading the agent entry/memory index, this task, positioning, integrated snapshot, integration gate and completed source/previous integration records. The decision, architecture, domain and evidence context loaded during the source task is at the identical main baseline. Existing 200 peer scopes remain as assessed; the source task is the only titlebar overlap, and old placeholder scopes remain unknown without a concrete dependency.
- Product goal: preserve the current cross-platform light Electron workspace. This integration restores Windows Code action/wordmark separation, not a new architecture or product direction. Positioning still contains placeholders; current AGENTS.md and verified implementation supply applicable boundaries.
- Plan: fast-forward to the exact verified source; confirm product identity; update only this integration record and Integrated Through; run the documentation drift gate and commit the integration record.
- Keep source task records read-only and preserve the three adopted documents outside commits. No push, packaging, deployment, subagents or unapproved checkout removal.
## Outcome
- Fast-forwarded local main from `a39fbc1619470ad8d47a1b9131b2cada5b940ec5` to the exact source `dae64e52b94f54c61b14d744ef6e6d0580af2d3a` without conflicts or product edits.
- The Windows Code browser/run controls, Makelore wordmark and caption controls now occupy separate regions. Imported the source task record unchanged and recorded the source commit under current-state.md / Integrated Through.
- Preserved all three existing untracked task documents outside commits. No push, package, deployment or installed-client update was performed.
## Verification
- Source is a direct child of the current main base, its worktree is clean, and its committed record is Ready for Integration. `git merge --ff-only` succeeded and `git diff --exit-code dae64e5 HEAD` confirmed the exact source tree immediately after merge.
- Adopted unchanged-source evidence from this conversation: 42 related unit tests; typecheck; scoped ESLint; Renderer/Main/Preload/utility Vite build; focused Windows titlebar and existing Code interaction E2E passed. Geometry checks cover default/minimum 1024 px widths, 125% zoom, browser opening/closing, sidebar collapse, running/idle and caption interaction.
- No product changes or merge conflicts required repeating the same source checks. Integration validation uses the official task-aware drift checker for unchanged imports, canonical write ownership and preserved adopted documents, plus `git diff --check`.
## Follow-ups
- User explicitly approved deleting source task `20260915-windows-logo-overlap-5106511f` at `D:\Datas\OthersProjects\.codex-worktrees\makelore\20260915-windows-logo-overlap-5106511f`, preserving branch `codex/20260915-windows-logo-overlap-5106511f-windows-logo-overlap` and commits. Before invoking bundled `retire`, verified the absolute target, clean source state, exact source HEAD and inclusion in main. Retirement failed with Git `Directory not empty`, leaving a partially removed directory (including dependency/source files) and no Git worktree listing for this path. Retained those residual files; did not bypass the skill with a manual recursive delete. The source branch and committed result remain intact. Cleanup is blocked on the supported retirement/recovery workflow; this does not block the completed merge.
- Rebuild and install the Windows client when an updated application is requested.
## Promotion Candidates
- No new architecture or domain rule. This integration records the verified Windows titlebar correction in the canonical integrated snapshot.
@@ -0,0 +1,51 @@
# Task: Fix Windows coding titlebar logo overlap
## Identity
- Task ID: 20260915-windows-logo-overlap-5106511f
- Mode: Feature
- Branch: codex/20260915-windows-logo-overlap-5106511f-windows-logo-overlap
- Worktree: D:\Datas\OthersProjects\.codex-worktrees\makelore\20260915-windows-logo-overlap-5106511f
- Base commit: a39fbc1619470ad8d47a1b9131b2cada5b940ec5
- Owner: codex
- Status: Ready for Integration
## Scope
- Reproduce and fix the Windows Code titlebar overlap between the Makelore wordmark and the developer-browser toggle. Cover the actual Renderer geometry with the shared Electron fixture.
## Intent And Constraints
- Concurrent Task Gate passed: bundled check/start/status succeeded and match this task's feature mode, branch, isolated worktree and base commit. Main is occupied by the platform-embedding integration task; all task operations remain in this linked worktree.
- Planning Gate passed after reading the agent entry and memory index, own task record, positioning, integrated state, decision index, system overview, business rules, success criteria, evidence index and previous Windows titlebar integration record.
- Read the Scope, Intent And Constraints and Promotion Candidates of the 200 registered peers. No concrete semantic conflict with this narrow layout correction was found. Several older peer records remain planning placeholders; their coordination scope is unknown. Do not modify them.
- Project positioning contains placeholders and some shared history describes retired modules. Use current AGENTS.md and implementation for product boundaries. The old titlebar source record is absent; its readable integration record documents the existing 148 px Windows control reservation.
- Keep the light visual system, Main-owned browser contract, platform chrome behavior and Code/Pi configuration boundaries. No subagents, package, deployment or unrelated cleanup.
- Plan: reproduce browser/wordmark geometry overlap in Electron, isolate the responsible spacing, make a narrow correction, then run related unit tests, typecheck, lint, build and Electron layout/interaction checks.
## Outcome
- Reproduced the reported Windows Code overlap against the built Electron app twice: the browser button ended at x=1084 while the wordmark started at x=1036. The minimized layout regression failed in 1.7 seconds before the fix.
- Root cause: CodingConversationHeader used the macOS-sized 160 px padding for both custom-titlebar platforms. Windows chrome needs 148 px for caption controls plus 96 px for the wordmark, so browser and run actions occupied the wordmark region.
- Shared the existing wordmark/caption dimensions in `src/components/layout/titlebar-metrics.ts`. Windows now ends the portaled conversation header at the wordmark boundary and retains its ordinary 12 px inner padding. This reserves space for all actions and keeps their hit area outside caption controls. macOS keeps its existing 160 px padding, and Linux keeps its inline header.
- Updated README's platform-specific titlebar description. No backend, runtime, persistence, application identity or canonical-memory change.
- Added a Windows Electron regression for geometry, browser open/close, sidebar collapse, active/settled run states, minimum window width, 125% zoom and real maximize/restore interaction. The existing broad Code UI test also checks browser/wordmark separation.
## Verification
- Toolchain: exact pinned pnpm 10.33.4; `pnpm install --frozen-lockfile` passed without lockfile changes.
- Red: `pnpm exec playwright test tests/e2e/pi-coding-first-chat.spec.ts --grep 'Windows Code titlebar' --reporter=list` failed on the actual overlapping button bounds before the fix. The earlier existing-UI assertion independently reproduced the same coordinates.
- Green: the same focused Electron command passed in 4.3 seconds. It covers 1280 px, the application's actual minimum of 1024 px, and 1280 px at 125% content zoom; browser open/closed; sidebar collapsed; running/idle; caption-control hit testing and maximize/restore. The initial test attempt used unsupported 1000 px and was corrected after confirming Main's 1024 px minimum; this was a fixture expectation, not a product defect.
- `pnpm exec playwright test tests/e2e/pi-coding-first-chat.spec.ts --grep 'PI feature UI isolates' --reporter=list`: passed on the fixed production build, including existing browser and Conversation interaction assertions.
- Related unit tests: `title-bar.test.tsx`, `coding-chat-panel.test.tsx`, `agent-browser-panel.test.tsx`: 3 files / 42 tests passed.
- `pnpm run typecheck`, scoped ESLint for all changed TypeScript files, `pnpm run build:vite` (Renderer/Main/Preload/utility), and `git diff --check`: passed.
- Visually inspected the default-size Electron screenshot at `test-results/pi-coding-first-chat-Windo-0b8c4-he-logo-and-window-controls/windows-code-titlebar.png`: browser and stop controls, wordmark and caption controls occupy separate regions. Screenshot/build outputs remain ignored.
- No full unit suite or packaged/installed-client verification was run; the focused tests cover the changed Renderer seam. No temporary product instrumentation was introduced.
## Follow-ups
- Integrate this source branch and rebuild the Windows client for the installed application to receive the correction. This task does not merge main, push or package.
## Promotion Candidates
- None. This restores the existing titlebar separation contract; the README already records the platform-specific behavior.
+1 -1
View File
@@ -144,7 +144,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 名称,必要的中止/恢复入口保留在右侧;不再展示 Pi 空闲/运行副标题。对话列表栏只显示项目名称和项目设置入口,不显示“Pi 本地对话”副标题;全局品牌 Logo 贴齐窗口最右边缘。归档、未读、整段 Conversation 分支和编程工具抽屉均不占用标题栏。从已持久化的 user 消息仍可“从这里创建新对话分支”,assistant 消息和未持久化消息不提供该动作;分支只创建新的 Conversation 历史,不表示文件回滚。Pi 的工具调用与浏览器附件继续在对应的对话过程节点中按需展开;分享、待办、全局运行时和 revert/unrevert 不属于该产品界面。
- 核心聊天页标题栏左侧只显示 Conversation 名称,必要的中止/恢复入口保留在右侧;不再展示 Pi 空闲/运行副标题。对话列表栏只显示项目名称和项目设置入口,不显示“Pi 本地对话”副标题;全局品牌 Logo 在 macOS 贴齐窗口最右边缘,在 Windows 位于窗口控制按钮左侧;Windows 的开发浏览器、中止和恢复按钮使用 Logo 左侧的独立区域。归档、未读、整段 Conversation 分支和编程工具抽屉均不占用标题栏。从已持久化的 user 消息仍可“从这里创建新对话分支”,assistant 消息和未持久化消息不提供该动作;分支只创建新的 Conversation 历史,不表示文件回滚。Pi 的工具调用与浏览器附件继续在对应的对话过程节点中按需展开;分享、待办、全局运行时和 revert/unrevert 不属于该产品界面。
## 运行内核与项目数据
+3 -4
View File
@@ -14,12 +14,10 @@ import { useCodingWorkspaceStore } from '@/stores/coding-workspace';
import { useSettingsStore } from '@/stores/settings';
import logoWordmarkSource from '@/assets/makelore-wordmark-source.png';
import type { SidebarPeekSource } from './sidebar-peek';
import { TITLEBAR_LOGO_WIDTH, WINDOWS_TITLEBAR_CONTROLS_WIDTH } from './titlebar-metrics';
type SidebarPeekChange = (open: boolean, source: SidebarPeekSource) => void;
// Three 44px buttons plus the control container's 8px padding on each side.
const WINDOWS_TITLEBAR_CONTROLS_WIDTH = 148;
type TitleBarProps = {
integrated?: boolean;
workspaceLayout?: boolean;
@@ -123,10 +121,11 @@ function ProductTitleBar({
<div
data-testid="titlebar-logo"
className={cn(
'pointer-events-none absolute top-1/2 z-10 h-6 w-24 -translate-y-1/2 overflow-hidden',
'pointer-events-none absolute top-1/2 z-10 h-6 -translate-y-1/2 overflow-hidden',
overlay ? 'bg-transparent' : 'bg-background',
)}
style={{
width: TITLEBAR_LOGO_WIDTH,
right: `${windowControlsWidth}px`,
}}
>
@@ -0,0 +1,4 @@
export const TITLEBAR_LOGO_WIDTH = 96;
// Three 44px buttons plus the control container's 8px padding on each side.
export const WINDOWS_TITLEBAR_CONTROLS_WIDTH = 148;
+8 -2
View File
@@ -20,6 +20,7 @@ import {
import { Input } from '@/components/ui/input';
import { cn } from '@/lib/utils';
import { useSettingsStore } from '@/stores/settings';
import { TITLEBAR_LOGO_WIDTH, WINDOWS_TITLEBAR_CONTROLS_WIDTH } from '@/components/layout/titlebar-metrics';
import type { ConversationSnapshot } from '@/types/coding-conversation';
import type { CodingConversationMetadata } from '@/types/coding-project';
@@ -110,7 +111,8 @@ export function CodingConversationHeader({
<header
className={cn(
'drag-region flex h-10 min-w-0 items-center gap-1 border-b border-border/80 px-3',
hasCustomTitleBar ? 'bg-transparent pr-40' : 'bg-background',
hasCustomTitleBar ? 'bg-transparent' : 'bg-background',
platform === 'darwin' && 'pr-40',
)}
data-testid="coding-conversation-header"
>
@@ -184,7 +186,11 @@ export function CodingConversationHeader({
<div
className="pointer-events-none fixed right-0 top-0 z-[80] h-10"
data-testid="coding-conversation-header-titlebar"
style={{ left: `${sidebarCollapsed ? WORKSPACE_COLUMN_WIDTH : WORKSPACE_COLUMN_WIDTH * 2}px` }}
style={{
left: `${sidebarCollapsed ? WORKSPACE_COLUMN_WIDTH : WORKSPACE_COLUMN_WIDTH * 2}px`,
// Keep both actions and their hit area outside the product chrome.
right: platform === 'win32' ? TITLEBAR_LOGO_WIDTH + WINDOWS_TITLEBAR_CONTROLS_WIDTH : 0,
}}
>
<div className="pointer-events-auto h-full">{header}</div>
</div>,
+77
View File
@@ -1119,6 +1119,78 @@ test('foreground focus rehydrates a terminal Snapshot after lifecycle sleep', as
))).toBe(false);
});
test('Windows Code titlebar keeps browser actions clear of the logo and window controls', async ({
launchElectronApp,
}) => {
test.skip(process.platform !== 'win32', 'Windows custom titlebar only');
const electronApp = await launchElectronApp({ skipSetup: true });
const page = await getStableWindow(electronApp);
const hostConnection = await page.evaluate(async () => ({
token: await window.electron.ipcRenderer.invoke('hostapi:token') as string,
baseUrl: await window.electron.ipcRenderer.invoke('hostapi:base-url') as string,
}));
await installCodingFirstChatHost(electronApp, hostConnection, true);
await disableCodingEventSource(page);
try {
await page.reload();
await page.getByTestId('ai-module-option-programming').click();
await expect(page.getByTestId('coding-conversation-header')).toBeVisible();
const header = page.getByTestId('coding-conversation-header');
const assertChromeClear = async () => {
const logo = await page.getByTestId('titlebar-logo').boundingBox();
expect(logo).not.toBeNull();
for (const button of await header.getByRole('button').all()) {
const bounds = await button.boundingBox();
expect(bounds).not.toBeNull();
expect(bounds!.x + bounds!.width).toBeLessThanOrEqual(logo!.x);
}
const minimize = page.getByTitle('Minimize');
const minimizeBounds = await minimize.boundingBox();
expect(minimizeBounds).not.toBeNull();
expect(logo!.x + logo!.width).toBeLessThanOrEqual(minimizeBounds!.x);
// The conversation header must not intercept clicks in the window controls.
for (const title of ['Minimize', 'Maximize', 'Close']) {
await page.getByTitle(title, { exact: true }).click({ trial: true });
}
};
for (const { width, zoom } of [
{ width: 1280, zoom: 1 },
{ width: 1024, zoom: 1 },
{ width: 1280, zoom: 1.25 },
]) {
await electronApp.evaluate(({ BrowserWindow }, dimensions) => {
const window = BrowserWindow.getAllWindows()[0];
window.setSize(dimensions.width, 800);
window.webContents.setZoomFactor(dimensions.zoom);
}, { width, zoom });
await expect.poll(async () => page.evaluate(() => window.innerWidth)).toBe(Math.round(width / zoom));
await assertChromeClear();
if (width === 1280 && zoom === 1) {
await page.screenshot({ path: test.info().outputPath('windows-code-titlebar.png') });
}
await header.getByRole('button', { name: '打开开发浏览器' }).click();
await expect(page.getByTestId('agent-browser-panel')).toBeVisible();
await assertChromeClear();
await header.getByRole('button', { name: '关闭开发浏览器' }).click();
await expect(page.getByTestId('agent-browser-panel')).toHaveCount(0);
}
await page.getByTestId('titlebar-sidebar-toggle').click();
await assertChromeClear();
await settleSnapshot(electronApp);
await page.evaluate(() => window.dispatchEvent(new FocusEvent('focus')));
await expect(header.getByRole('button', { name: '中止', exact: true })).toHaveCount(0);
await assertChromeClear();
await page.getByTitle('Maximize', { exact: true }).click();
await expect(page.getByTitle('Restore', { exact: true })).toBeVisible();
await page.getByTitle('Restore', { exact: true }).click();
await expect(page.getByTitle('Maximize', { exact: true })).toBeVisible();
} finally {
await releaseSnapshot(electronApp);
}
});
test('PI feature UI isolates Conversations and exposes queue, interaction, model, and subagent state', async ({
launchElectronApp,
}) => {
@@ -1167,6 +1239,11 @@ test('PI feature UI isolates Conversations and exposes queue, interaction, model
await expect(conversationHeader.getByRole('button', { name: '打开编程工具' })).toHaveCount(0);
const browserToggle = conversationHeader.getByRole('button', { name: '打开开发浏览器' });
await expect(browserToggle).toBeVisible();
if (process.platform === 'win32') {
const browserBounds = await browserToggle.boundingBox();
expect(browserBounds).not.toBeNull();
expect(browserBounds!.x + browserBounds!.width).toBeLessThanOrEqual(logoBounds!.x);
}
await browserToggle.click();
await expect(page.getByTestId('agent-browser-panel')).toBeVisible();
await expect(page.getByTestId('agent-browser-diagnostics')).toHaveAttribute('data-state', 'closed');