From bcbf398b658419239674e1ffb904ce8da76a92fe Mon Sep 17 00:00:00 2001 From: Linghong Date: Tue, 15 Sep 2026 07:05:46 +0000 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E9=80=80=E5=BD=B9=E7=AD=96?= =?UTF-8?q?=E5=88=92=E7=95=8C=E9=9D=A2=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 删除旧 GDD 审批卡与策划窄条的孤儿 CSS 更新聊天布局测试以覆盖现役 DirectCodex 选择器 保留设计 Agent 和通用项目工作台表现 --- .../src/features/agent-runtime/model.ts | 1 - apps/ai-game-creator-shell/src/styles.css | 393 +----------------- .../tests/chatDialogFrameLayout.test.ts | 10 +- 3 files changed, 5 insertions(+), 399 deletions(-) diff --git a/apps/ai-game-creator-shell/src/features/agent-runtime/model.ts b/apps/ai-game-creator-shell/src/features/agent-runtime/model.ts index 4c331835c..040cc7160 100644 --- a/apps/ai-game-creator-shell/src/features/agent-runtime/model.ts +++ b/apps/ai-game-creator-shell/src/features/agent-runtime/model.ts @@ -818,7 +818,6 @@ export const AGENT_RUNTIME_PLAN_SUBMIT_GDD_TOOL = 'plan.submit_gdd'; // 屏障处按信封原文构造这个 pending(`ensure_static_delegate_user_input_wait_at_locked`), // 同一份问题再投影成 `userInputRequest`,交互面是问答卡。 // - `plan.submit_gdd`:策划子 Agent 提交 Fast GDD 后,`planning/pending.json` 的 -// `submission.pendingActionId` 指向的正是这个 pending,交互面是 `GddApprovalCard` // 的批准 / 修改 / 退回。 // // 两者都没有「确认 / 拒绝」语义:`user.input_request` 从来不在 diff --git a/apps/ai-game-creator-shell/src/styles.css b/apps/ai-game-creator-shell/src/styles.css index 8f92d51fe..f05138012 100644 --- a/apps/ai-game-creator-shell/src/styles.css +++ b/apps/ai-game-creator-shell/src/styles.css @@ -9269,115 +9269,6 @@ iframe.preview-frame { } } -/* ============================================================ - 立项策划前端样式(PlanGddSurface / 阶段进度 / GDD 审批卡 / 交付行 / - planning-lane-runtime-strip)。 - 这一段曾在 #193「Codex/agent chat layout fix」重写聊天样式时被整体误删: - 组件(TSX)原样保留、选择器全数消失,策划界面裸奔、正文弹层失去 fixed 定位 - 变成内联平铺。从 5802048c3^ 原样恢复。聊天区样式重构时请勿顺手清理本段—— - 这些选择器的使用方在 features/project-workspace/GddApprovalCard.tsx 与 - PlanningLaneRuntimeStrip.tsx。 - ============================================================ */ - -/* 策划区是一个面:阶段进度是标题栏,审批卡是正文。边框和圆角只画在外壳上,里面两块 - 不再各自带框。 */ -.plan-gdd-surface { - display: grid; - min-width: 0; - border: 1px solid #cfd7e6; - border-radius: 10px; - background: #fff; - overflow: hidden; -} - -.gdd-approval-card { - display: grid; - gap: 14px; - padding: 16px 18px 18px; - background: #f8fbff; -} - -.plan-gdd-surface--with-card .plan-gdd-stage-progress { - border-bottom: 1px solid #dbe4f1; -} - -.plan-gdd-stage-progress { - display: grid; - gap: 6px; - padding: 10px 12px; - background: #fff; - color: #526173; - font-size: 12px; -} - -.plan-gdd-stage-progress__header, -.plan-gdd-stage-progress__meta { - display: flex; - flex-wrap: wrap; - align-items: center; - justify-content: space-between; - gap: 8px 14px; -} - -/* 批准后的交付行。它是策划阶段唯一的产物出口,所以给一条分隔线把它和上面的状态 - 区分开,而不是混成第三行元信息。 */ -.plan-gdd-stage-progress__delivery { - display: grid; - gap: 8px; - margin-top: 4px; - padding-top: 9px; - border-top: 1px solid #e6ecf5; -} - -.plan-gdd-stage-progress__delivery code { - min-width: 0; - color: #3c4a5c; - font-size: 11px; - overflow-wrap: anywhere; -} - -.plan-gdd-stage-progress__delivery-actions { - display: flex; - flex-wrap: wrap; - gap: 8px; -} - -.plan-gdd-stage-progress__delivery-actions button { - min-height: 30px; - padding: 0 12px; - border: 1px solid #cfd7e6; - border-radius: 6px; - color: #27364a; - background: #fff; - font-size: 12px; -} - -.plan-gdd-stage-progress__delivery-actions button:hover:not(:disabled), -.plan-gdd-stage-progress__delivery-actions button:focus-visible { - border-color: #1f6feb; - color: #1f6feb; -} - -.plan-gdd-stage-progress__delivery-actions button:disabled { - opacity: 0.58; -} - -.plan-gdd-stage-progress__delivery-error { - color: #b42323; - overflow-wrap: anywhere; -} - -.plan-gdd-stage-progress__header strong { - color: #27364a; -} - -.plan-gdd-stage-progress__header span { - padding: 3px 8px; - border-radius: 999px; - background: #eef6ff; - color: #1f6feb; -} - .design-agent-approval, .design-agent-clarify { display: flex; @@ -9910,283 +9801,6 @@ button.design-workspace-tree__entry:hover, } } -.gdd-approval-card__header { - display: grid; - gap: 5px; - min-width: 0; -} - -.gdd-approval-card h2, -.gdd-approval-card h3, -.gdd-approval-card p { - margin: 0; -} - -.gdd-approval-card h2 { - font-size: 18px; -} - -.gdd-approval-card__header p { - color: #526173; - overflow-wrap: anywhere; -} - -.gdd-approval-card__details-trace { - color: #6b7a8c; - font-size: 11px; - overflow-wrap: anywhere; -} - -.gdd-approval-card__details-trigger { - justify-self: start; - min-height: 30px; - padding: 0 10px; - border: 1px solid #cfd7e6; - border-radius: 6px; - color: #27364a; - background: #fff; -} - -.gdd-approval-card__decisions { - display: grid; - gap: 8px; -} - -.gdd-approval-card__decisions article { - display: grid; - gap: 3px; - padding: 9px 10px; - border: 1px solid #e2e8f0; - border-radius: 7px; - background: #fff; -} - -.gdd-approval-card__decisions article span { - color: #1f6feb; - font-size: 12px; -} - -.gdd-approval-card__decisions article small { - color: #526173; - overflow-wrap: anywhere; -} - -.gdd-approval-card__actions, -.gdd-approval-card__dialog-actions, -.gdd-approval-card__recovery { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 8px; -} - -.gdd-approval-card__actions button, -.gdd-approval-card__dialog-actions button, -.gdd-approval-card__recovery button { - min-height: 32px; - padding: 0 12px; - border: 1px solid #cfd7e6; - border-radius: 6px; - color: #fff; - background: #1f6feb; -} - -.gdd-approval-card__actions button:nth-child(n + 2), -.gdd-approval-card__dialog-actions button:first-child { - color: #27364a; - background: #fff; -} - -.gdd-approval-card button:disabled { - cursor: not-allowed; - opacity: 0.55; -} - -.gdd-approval-card__recovery { - justify-content: space-between; - padding: 9px 10px; - border-radius: 7px; - color: #854d0e; - background: #fff7df; - font-size: 13px; -} - -.gdd-approval-card__error { - padding: 9px 10px; - border-radius: 7px; - color: #991b1b; - background: #fff1f2; - overflow-wrap: anywhere; -} - -.gdd-approval-card__dialog-backdrop { - position: fixed; - top: var(--window-chrome-height); - right: 0; - bottom: 0; - left: 0; - z-index: 220; - display: grid; - padding: 24px; - background: rgb(0 0 0 / 56%); - place-items: center; -} - -.gdd-approval-card__dialog { - display: grid; - gap: 12px; - width: min(520px, 100%); - padding: 20px; - border: 1px solid #e5e7eb; - border-radius: 8px; - background: #fff; - box-shadow: 0 18px 52px rgb(0 0 0 / 18%); -} - -.gdd-approval-card__details { - max-height: min(760px, calc(100vh - 32px)); - overflow: auto; -} - -.gdd-approval-card__details header, -.gdd-approval-card__details article { - display: grid; - gap: 5px; -} - -.gdd-approval-card__details article { - padding-top: 10px; - border-top: 1px solid #e2e8f0; -} - -.gdd-approval-card__details p { - white-space: pre-line; - overflow-wrap: anywhere; -} - -.gdd-approval-card__dialog textarea { - width: 100%; - min-height: 110px; - padding: 9px; - border: 1px solid #cfd7e6; - border-radius: 6px; - resize: vertical; -} - -.gdd-approval-card__dialog-hint { - padding: 9px 10px; - border-radius: 7px; - color: #854d0e; - background: #fff7df; - font-size: 13px; -} - -/* 审批卡是这一列里唯一没有天花板的成员:Fast GDD 的决定项越多它越高,能把消息列表和运行 - 时面板一起挤出可视区。和 `.agent-runtime-status` 一样给它自己的上限加内部滚动,而不是 - 让它去挤别人。 */ -/* 策划链路的会话列比另外两条多一个成员:策划面(阶段进度 + 审批卡)。#193(5802048c3 - 「Codex/agent chat layout fix」)把这个容器从基础规则继承来的 `display: grid` 改成 - `display: block`、并把消息列表从 `flex: 1 1 auto` 改成 `height: 100%`,于是列表独吞 - 整列高度,排在它后面的策划窄条、待确认命令、输入框和状态行全部被 `overflow: hidden` - 静默裁掉——组件照常渲染、DOM 里查得到,只是位置落在裁剪线外,屏幕上什么都没有。 - 实测:窄条 top=858 而容器 bottom=788,超出 384px;scrollHeight 1235 vs clientHeight 734。 - - 同一批改动还删掉了 `.game-workbench-chat .project-supervisor-composer` 的 4 条规则, - 所以列表上那个 `padding-bottom: 196px`(本意是给「浮起来的输入框」留位)从来没有对应 - 的定位规则,那个模型压根没成立过。 - - 命中判据是两个类的并集,两个都只属于策划链路,做游戏与做素材保持 master 的 block - 列原样不动。为什么不能只认策划面:`PlanGddSurface` 在 `planGddState === null` 时整个 - 返回 null,而 `planGddState` 初值就是 null、要靠一次独立的 IPC 才填上。首帧竞态、以及 - hydrate 持续失败时,策划 run 照跑、澄清卡照渲染,只认策划面就会漏掉这一格,裁剪原样 - 复发。窄条自己在场就等价于「有东西要用户动手」,把它并进来之后,「卡片存在」和「列 - 布局生效」才是同一件事。 - - 用 flex 列而不是 grid:子元素个数随待确认命令的有无浮动,固定行模板会错位;而且下面 - 那条 `.plan-gdd-surface { flex: 0 0 auto }` 本来就是照 flex 写的,容器变成 flex 之后它 - 才真正生效——在此之前它一直是死声明。 */ -.game-workbench-chat - .project-supervisor-conversation:has( - .plan-gdd-surface, - .planning-lane-runtime-strip - ) { - display: flex; - flex-direction: column; - gap: 10px; - /* 兜底:正常情况下上面的行分配已经让整列放得下,这条不会产生滚动条。但审批卡展开 - 到 52dvh 且窄条同时在场时仍可能超出,届时给滚动而不是继承 `overflow: hidden` - 的裁剪——这个 bug 的全部代价就来自「悄悄裁掉」,宁可多一根滚动条。 */ - overflow-y: auto; -} - -/* 整列里只有消息列表可收缩:其余成员各自有天花板(策划面按内容、窄条 52dvh 且内滚、 - 输入框定高),由列表吸收剩余空间。`height: 100%` 必须撤掉,否则它照旧独吞整列; - `padding-bottom` 也一并收回,输入框已经回到文档流里,不再需要给它留空。 */ -.game-workbench-chat - .project-supervisor-conversation:has( - .plan-gdd-surface, - .planning-lane-runtime-strip - ) - .project-supervisor-message-list { - flex: 1 1 auto; - height: auto; - min-height: 96px; - padding-bottom: 12px; - scroll-padding-bottom: 12px; -} - -/* 这三个成员不参与压缩:消息列表变长时不能把它们挤没——它们正是用户唯一需要动手的 - 地方(澄清卡、输入框)。 */ -.game-workbench-chat - .project-supervisor-conversation:has( - .plan-gdd-surface, - .planning-lane-runtime-strip - ) - .planning-lane-runtime-strip, -.game-workbench-chat - .project-supervisor-conversation:has( - .plan-gdd-surface, - .planning-lane-runtime-strip - ) - .project-supervisor-composer, -.game-workbench-chat - .project-supervisor-conversation:has( - .plan-gdd-surface, - .planning-lane-runtime-strip - ) - .project-supervisor-workspace-status { - flex: 0 0 auto; -} - -/* 这个面不参与 flex 压缩。它自己不会长高:标题栏是固定几行,审批卡下面有自己的 - max-height 和内滚,所以高度天然有界。让它可压缩的话,`overflow: hidden`(画圆角 - 要的)会把底部切掉——批准后交付行正好在那儿,表现是路径和两个按钮凭空消失。 */ -.game-workbench-chat .plan-gdd-surface { - flex: 0 0 auto; -} - -/* 只有审批卡在场时才需要「标题栏定高 + 正文占余下」的两行轨道。批准后卡片收掉, - 面里只剩标题栏,这条声明会给它套上一个不存在的第二行。 */ -.game-workbench-chat .plan-gdd-surface--with-card { - min-height: 0; - grid-template-rows: auto minmax(0, 1fr); -} - -.game-workbench-chat .gdd-approval-card { - min-height: 0; - max-height: clamp(240px, 52dvh, 640px); - overflow-y: auto; - overscroll-behavior: contain; - scrollbar-gutter: stable; -} - -/* 上面 24dvh/240px 的天花板是给做游戏链路常驻的调试面板设的。策划链路的窄条只在 - 需要用户动手时出现(澄清卡 / 失败恢复),内容是要读完再回答的题面,给它和审批 - 卡同级的空间。 */ -.game-workbench-chat .planning-lane-runtime-strip { - max-height: clamp(240px, 52dvh, 640px); -} - /* 做方案在拿到第一个已登记资源之前,左边的资源画布是空的;工作台此时收成单栏, 对话铺满。类名由 view/project-development/index.tsx 的 conversationOnlyWorkbench 拼上(planningStartMode && resources.length === 0),画布是 display: none 不是 @@ -10675,11 +10289,8 @@ button.design-workspace-tree__entry:hover, color: var(--platform-button-primary-text); } -/* 对话框盒子的最终几何,故意放在文件靠后的位置:它与上面那条同选择器同权重 - (`.game-workbench-chat .project-supervisor-surface.is-direct-codex - .project-supervisor-message-list`),按"后写胜出"把两处会顶掉它的规则压回去—— - 一是 `:has(.plan-gdd-surface, .planning-lane-runtime-strip)` 给列表留的 - `padding-bottom: 12px`,二是下面窄屏块之前可能出现的任何底边偏移。 +/* 对话框盒子的最终几何,故意放在文件靠后的位置:它与上面的同选择器同权重,按 + "后写胜出"把窄屏块之前可能出现的任何底边偏移压回去。 这里曾经是一条 `bottom: 156px`("列表在上、输入区在下"那版两盒布局的残留:给下面那只 浮起来的输入区预留高度),它把上面那条 `bottom: 0` 悄悄顶掉,外框底边落在输入区腰上、 输入区下半截露在框外——用户看到的就是"外框底边与输入区压在一起、没把输入区包住"。 diff --git a/apps/ai-game-creator-shell/tests/chatDialogFrameLayout.test.ts b/apps/ai-game-creator-shell/tests/chatDialogFrameLayout.test.ts index bae420fcc..65607d2a7 100644 --- a/apps/ai-game-creator-shell/tests/chatDialogFrameLayout.test.ts +++ b/apps/ai-game-creator-shell/tests/chatDialogFrameLayout.test.ts @@ -112,10 +112,6 @@ const COMPOSER_EDITOR = `${COMPOSER_PLAIN} .resource-reference-input-editor`; const COMPOSER_CONTROLS = `${COMPOSER} .project-supervisor-composer-controls`; const COMPOSER_SUBMIT = `${COMPOSER_CONTROLS} .project-supervisor-submit-button`; const INPUT_ACTIONS = `${COMPOSER} .resource-reference-input-actions`; -// 策划链在会话列里额外挂了一条规划面/窄条时,列表会命中这条 `:has(...)` 规则—— -// 它同样声明了 `padding-bottom`,正是上一轮把留白改回 12px 的那种隐患。 -const LIST_WITH_PLAN_SURFACE = `.game-workbench-chat .project-supervisor-conversation:has(.plan-gdd-surface, .planning-lane-runtime-strip) .project-supervisor-message-list`; - const DESKTOP = 1440; const MOBILE = 390; @@ -186,7 +182,7 @@ function composerMaxHeight() { describe('陶泥儿对话区:外框完整包住输入区', () => { it('外框四边贴会话区,输入区四边都在外框之内且不重合(宽屏)', () => { - const list = desktopDeclarations(MESSAGE_LIST, LIST_WITH_PLAN_SURFACE); + const list = desktopDeclarations(MESSAGE_LIST); const composer = desktopDeclarations(COMPOSER, COMPOSER_PLAIN); // 先看不重合关系再钉绝对位移:底边必须"外框在外、输入区在内",留白 > 0。 @@ -238,7 +234,7 @@ describe('陶泥儿对话区:外框完整包住输入区', () => { }); it('消息列表底部留白 = 输入区内缩 + 输入区最高高度 + 间距,且与 scroll-padding 同值', () => { - const list = desktopDeclarations(MESSAGE_LIST, LIST_WITH_PLAN_SURFACE); + const list = desktopDeclarations(MESSAGE_LIST); const composer = desktopDeclarations(COMPOSER, COMPOSER_PLAIN); const { total, actionsRowHeight } = composerMaxHeight(); @@ -260,7 +256,7 @@ describe('陶泥儿对话区:外框完整包住输入区', () => { it('窄屏把外框交给会话列,输入区回到文档流,四周仍有一圈边距(390px)', () => { const conversation = mobileDeclarations(CONVERSATION); - const list = mobileDeclarations(MESSAGE_LIST, LIST_WITH_PLAN_SURFACE); + const list = mobileDeclarations(MESSAGE_LIST); const composer = mobileDeclarations( COMPOSER, COMPOSER_PLAIN,