+

+
与陶泥儿的对话
{professionalDagVisible ? '项目总控 Agent' : '智能创作'}
+ {walletEntry ? (
+
{walletEntry}
+ ) : null}
{professionalDagVisible ? (
{resourceLabel ?? 'UI 设计'}
-
+
+ {walletEntry ? (
+
{walletEntry}
+ ) : null}
+
+
) : null}
{session.save.saveError ? (
diff --git a/apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts b/apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts
index 9507775bb..be543b01c 100644
--- a/apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts
+++ b/apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts
@@ -3429,7 +3429,13 @@ export function registerProjectWorkbenchFoundationTests() {
);
expect(styles).toMatch(
- /\.game-project-workbench\s*\{[^}]*width:\s*calc\(100vw - 72px\)[^}]*padding:\s*72px 8px 8px[^}]*overflow:\s*hidden/s,
+ /\.game-project-workbench\s*\{[^}]*width:\s*calc\(100vw - var\(--launcher-sidebar-width\)\)[^}]*padding:\s*0[^}]*overflow:\s*hidden/s,
+ );
+ expect(styles).toMatch(
+ /\.launcher-main:has\(\.game-project-workbench\)\s*\{[^}]*padding-bottom:\s*0/s,
+ );
+ expect(styles).toMatch(
+ /\.game-workbench-toolbar\s*\{[^}]*padding:\s*8px 12px[^}]*background:\s*transparent/s,
);
expect(styles).toMatch(
/@media \(min-width: 761px\)[\s\S]*?\.game-project-workbench\s*\{[^}]*grid-template-rows:\s*minmax\(0, 1fr\) auto[^}]*height:\s*100dvh/,
@@ -3444,8 +3450,12 @@ export function registerProjectWorkbenchFoundationTests() {
/\.game-workbench-chat \.project-runtime-summary\s*\{[^}]*position:\s*sticky[^}]*top:\s*-10px/s,
);
expect(styles).toMatch(
- /\.game-workbench-chat \.project-supervisor-composer\s*\{[^}]*grid-template-columns:\s*minmax\(0, 1fr\) 82px[^}]*z-index:\s*2[^}]*border-top:\s*1px solid var\(--platform-line-soft\)/s,
+ /\.game-workbench-chat \.project-supervisor-composer\s*\{[^}]*grid-template-columns:\s*minmax\(0, 1fr\) 82px[^}]*z-index:\s*2[^}]*padding-top:\s*8px[^}]*background:\s*transparent/s,
);
+ const composerRule = styles.match(
+ /\.game-workbench-chat \.project-supervisor-composer\s*\{([^}]*)\}/s,
+ );
+ expect(composerRule?.[1]).not.toContain('border-top:');
expect(styles).toMatch(
/\.game-workbench-chat \.project-supervisor-composer button\s*\{[^}]*min-height:\s*72px[^}]*white-space:\s*nowrap/s,
);
@@ -3482,6 +3492,41 @@ export function registerProjectWorkbenchFoundationTests() {
);
});
+ it('keeps the wallet entry available when the workbench opens the UI editor', () => {
+ const styles = readFileSync(
+ resolve(process.cwd(), 'apps/ai-game-creator-shell/src/styles.css'),
+ 'utf8',
+ );
+ const projectDevelopmentSource = readFileSync(
+ resolve(
+ process.cwd(),
+ 'apps/ai-game-creator-shell/src/view/project-development/index.tsx',
+ ),
+ 'utf8',
+ );
+
+ expect(styles).toMatch(
+ /\.launcher-main:has\(\.game-project-workbench\)\s*>\s*\.launcher-account-bar\s*\{[^}]*display:\s*none/s,
+ );
+ expect(projectDevelopmentSource).toMatch(
+ /
/,
+ );
+ expect(projectDevelopmentSource).toMatch(
+ /
\{walletEntry\}<\/div>/,
+ );
+ });
+
+ it('keeps resource sort tab keyboard focus inside the clipped segmented control', () => {
+ const styles = readFileSync(
+ resolve(process.cwd(), 'apps/ai-game-creator-shell/src/styles.css'),
+ 'utf8',
+ );
+
+ expect(styles).toMatch(
+ /\.game-workbench-tabs\.game-resource-sort-tabs button:focus-visible\s*\{[^}]*box-shadow:\s*inset 0 0 0 3px var\(--platform-input-focus-ring\)/s,
+ );
+ });
+
it('keeps workbench chat bubbles aligned without shrinking process cards', () => {
const styles = readFileSync(
resolve(process.cwd(), 'apps/ai-game-creator-shell/src/styles.css'),
@@ -9200,7 +9245,8 @@ export function registerProjectSupervisorSurfaceTests() {
projectPath,
});
let directTurnUpdateHandler:
- ((event: { payload: Record }) => void) | null = null;
+ | ((event: { payload: Record }) => void)
+ | null = null;
const listen = vi.fn(
async (
eventName: string,
@@ -10157,7 +10203,8 @@ export function registerProjectAgentStatusTests() {
},
);
let runtimeUpdateHandler:
- ((event: { payload: Record }) => void) | null = null;
+ | ((event: { payload: Record }) => void)
+ | null = null;
const listen = vi.fn(
async (
eventName: string,
diff --git a/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts b/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts
index d7510084e..45351babe 100644
--- a/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts
+++ b/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts
@@ -146,6 +146,34 @@ async function renderLoadedSession(state: State) {
}
describe('UiEditorPage', () => {
+ it('keeps the wallet entry in the resource editor header', async () => {
+ const stateStore: IUiDesignStateStore = {
+ load: vi.fn().mockResolvedValue(structuredClone(EMPTY_SNAPSHOT)),
+ save: vi.fn(),
+ };
+
+ render(
+ createElement(UiEditorPage, {
+ projectPath: '/tmp/ui-editor-wallet',
+ resourceId: 'ui-resource',
+ stateStore,
+ walletEntry: createElement(
+ 'button',
+ { type: 'button', 'aria-label': '打开账户资产' },
+ '泥点',
+ ),
+ }),
+ );
+
+ const walletEntry = await screen.findByRole('button', {
+ name: '打开账户资产',
+ });
+ expect(walletEntry.closest('header')).not.toBeNull();
+ expect(
+ screen.getAllByRole('button', { name: '打开账户资产' }),
+ ).toHaveLength(1);
+ });
+
it('cancels image preview scopes when the resource changes and on unmount', async () => {
vi.mocked(invoke)
.mockReset()
diff --git a/docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md b/docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md
index 1210b16e9..bbfe89dca 100644
--- a/docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md
+++ b/docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md
@@ -108,6 +108,9 @@
- 第一批共享 chrome 固定覆盖画布动作按钮、工具栏、工具分组和分隔符。按钮的默认、悬停、键盘焦点、选中、禁用和主次色语义由共享层表达;宿主只提供图标、文案、事件与业务禁用条件。
- 主站账号、钱包、服务端项目、云端素材库和生成面板仍留在网站宿主;客户端本地项目、manifest、Runtime、审批、草稿、生成与正式提交仍留在 Tauri 宿主。共享视觉组件不得读取这些业务事实。
- 客户端 UI 对齐采用“同视觉、同组件、保留四区布局”,不复制主站整页布局。资源总览、运行视图和 Supervisor 对话继续是 Game Agent 工作台独有语义。
+- 工作台四区作为同一应用工作面直接衔接,外层不使用卡片圆角或留白间距。中央主视窗与右侧 Supervisor 使用各自的平台区域底色,并以稳定的竖向分隔线明确边界;不通过外层圆角容器、阴影或区块间缝重新包装四区。
+- 右侧正式钱包入口属于客户端宿主 chrome,在普通项目工作台与 UI Editor 子路由中都必须持续可见、键盘可达且可操作,不得因进入素材编辑壳或隐藏全局 chrome 而丢失余额、充值和使用详情入口。
+- 资源总览的“资源依赖 / 资源类型”视图切换使用连通的分段按钮组,相邻选项共享边界并保持唯一选中语义。每个分段都必须有清晰的键盘焦点指示,焦点环不得被分段容器的圆角或 `overflow` 裁切。
- 右侧 Supervisor 对话中,用户消息使用右对齐、最大宽度受限的主题暖色气泡,assistant 消息保持左对齐;消息换行不得产生水平溢出,执行过程卡继续占满消息区可用宽度。气泡正文在 light / dark 平台主题下均须满足 WCAG AA 普通文本 `4.5:1` 对比度。
- 客户端正式产品仍只按最小 `1280×720` 横屏合同交付,并保留 `1280×800` 默认窗口与既有基线验收;更窄浏览器样式只负责不崩溃和开发兼容,不改成移动端创作工作台。
- 普通用户界面不默认展示内部错误码或本机绝对路径,也不展示 External Editor Base URL 或 Developer API Key;官方服务地址由客户端构建固定,远端编辑自动使用当前陶泥儿登录态。仅独立 standalone game-chat release 或显式高级自定义模式在隔离配置页维护 External v1 URL/Key,确需诊断的信息进入受控详情或开发模式。
@@ -567,6 +570,9 @@ type ProjectAgentMudPointAttribution = {
4. 主站现有图片编辑器的按钮名称、tool selection、hover/focus/pressed/disabled 行为与工具栏位置不因共享抽取回归;网站账号、钱包、素材库、生成和导出逻辑不下沉共享层。
5. 客户端生成、保存、取消、恢复、登录失效与余额不足只更换视觉承载,不改变 Host Port 调用、幂等身份、草稿 CAS、manifest/revision、Runtime 审批或钱包刷新语义。
6. 阶段一、二冻结合同并让主站消费共享 chrome;2026-08-06 的阶段三至五已经完成客户端中央区、Supervisor 和 Agent Dock 的正式换肤、定向测试与 `1280×800` 验收。独立 Vite 没有登录会话时继续显示真实登录门禁,不为视觉测试增加绕过入口。
+7. 普通工作台和 UI Editor 子路由均不显示工作面外层圆角或区块留白;中央区与右侧 Supervisor 的区域底色可辨识,竖向分隔连续、无错位。
+8. 右侧正式钱包入口在普通工作台和 UI Editor 子路由都始终可见、键盘可达并能打开余额、充值与使用详情;路由切换不得使入口消失或失去交互。
+9. “资源依赖 / 资源类型”以连通分段按钮呈现,点击与键盘操作均只保留一个选中项;使用 Tab 定位和键盘切换时焦点指示清晰、完整,不被容器边界或 `overflow` 裁切。
## 8. 非目标