Merge branch 'master' into codex/home-inspiration-gallery
Project CI / Frontend tests (pull_request) Failing after 3m38s
Project CI / Repository checks (pull_request) Failing after 4m31s
Project CI / Backend tests (pull_request) Successful in 6m38s
Project CI / Native shell tests (pull_request) Failing after 3m46s

This commit is contained in:
2026-08-26 16:55:49 +08:00
6 changed files with 218 additions and 2 deletions
@@ -0,0 +1,5 @@
import appPackage from '../../package.json';
/** Product metadata shared by the client UI and release bundle. */
export const APP_NAME = 'Genarrative AI Game Creator';
export const APP_VERSION = appPackage.version;
@@ -3,6 +3,7 @@ import {
Cable,
CheckCircle2,
CircleAlert,
Info,
LoaderCircle,
RotateCcw,
Save,
@@ -13,6 +14,8 @@ import {
import { type FormEvent, useEffect, useRef, useState } from 'react';
import { createGameCreationAppSeedTasks } from '../../../../../packages/shared/src/contracts/gameCreationApp';
import BRAND_ICON from '../../../../../packages/shared/src/icons/taonier-product-ip.png';
import { APP_NAME, APP_VERSION } from '../../app/appMetadata';
import {
closeDialogOnBackdropMouseDown,
closeDialogOnEscape,
@@ -79,7 +82,12 @@ const defaultRuntimeConfigDraft: GameCreatorAppConfig = {
},
};
type RuntimeSettingsSection = 'general' | 'agents' | 'connections' | 'advanced';
type RuntimeSettingsSection =
| 'general'
| 'agents'
| 'connections'
| 'advanced'
| 'about';
type RuntimeConfigToast = {
tone: 'success' | 'error';
@@ -111,6 +119,12 @@ const runtimeSettingsSections = [
description: '上下文、超时与重试',
icon: SlidersHorizontal,
},
{
id: 'about',
label: '关于',
description: '客户端信息',
icon: Info,
},
] as const satisfies ReadonlyArray<{
id: RuntimeSettingsSection;
label: string;
@@ -1258,6 +1272,44 @@ export function RuntimeConfigDialog({
) : null}
</section>
) : null}
{activeSection === 'about' ? (
<section
className="runtime-settings-about"
aria-label="关于客户端"
>
<div className="runtime-settings-about-hero">
<div
className="runtime-settings-about-mark"
aria-hidden="true"
>
<img
src={BRAND_ICON}
alt=""
data-testid="runtime-settings-app-logo"
/>
</div>
<div>
<span className="runtime-settings-about-kicker">
GENARRATIVE
</span>
<h4>{APP_NAME}</h4>
<p></p>
</div>
</div>
<dl className="runtime-settings-about-meta">
<div>
<dt></dt>
<dd data-testid="runtime-settings-app-version">
v{APP_VERSION}
</dd>
</div>
<div>
<dt></dt>
<dd></dd>
</div>
</dl>
</section>
) : null}
</div>
</main>
</div>
+105
View File
@@ -3212,6 +3212,101 @@ h2 {
box-shadow: 0 0 0 3px var(--platform-input-focus-ring);
}
.runtime-settings-about {
grid-column: 1 / -1;
display: grid;
gap: 14px;
max-width: 680px;
}
.runtime-settings-about-hero {
display: flex;
align-items: center;
gap: 18px;
min-height: 158px;
padding: 24px;
border: 1px solid var(--platform-subpanel-border);
border-radius: 16px;
background: var(--runtime-settings-subpanel-fill);
}
.runtime-settings-about-mark {
display: grid;
flex: 0 0 auto;
width: 72px;
height: 72px;
border: 1px solid var(--platform-nav-active-border);
border-radius: 20px;
background: var(--platform-nav-active-fill);
color: var(--platform-accent);
font-size: 32px;
font-weight: 900;
letter-spacing: -0.08em;
place-items: center;
box-shadow: var(--platform-nav-active-shadow);
}
.runtime-settings-about-mark img {
width: 100%;
height: 100%;
object-fit: contain;
transform: scale(1.35);
}
.runtime-settings-about-hero > div:last-child {
display: grid;
gap: 5px;
min-width: 0;
}
.runtime-settings-about-kicker {
color: var(--platform-accent);
font-size: 10px;
font-weight: 900;
letter-spacing: 0.16em;
}
.runtime-settings-about-hero h4 {
margin: 0;
color: var(--platform-text-strong);
font-size: 20px;
letter-spacing: -0.03em;
}
.runtime-settings-about-hero p {
margin: 0;
color: var(--platform-text-soft);
font-size: 12px;
}
.runtime-settings-about-meta {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
margin: 0;
}
.runtime-settings-about-meta > div {
display: grid;
gap: 7px;
padding: 14px;
border: 1px solid var(--platform-subpanel-border);
border-radius: 12px;
background: var(--runtime-settings-subpanel-fill);
}
.runtime-settings-about-meta dt {
color: var(--platform-text-soft);
font-size: 10px;
}
.runtime-settings-about-meta dd {
margin: 0;
color: var(--platform-text-strong);
font-size: 14px;
font-weight: 800;
}
.runtime-agent-list {
grid-column: 1 / -1;
display: grid;
@@ -4034,6 +4129,16 @@ iframe.preview-frame {
grid-template-columns: 1fr;
}
.runtime-settings-about-hero {
align-items: flex-start;
flex-direction: column;
min-height: 0;
}
.runtime-settings-about-meta {
grid-template-columns: 1fr;
}
.runtime-agent-card-summary > span:last-child {
max-width: 48%;
text-align: right;
@@ -1,3 +1,4 @@
import { APP_VERSION } from '../../src/app/appMetadata';
import {
act,
createGameCreationAppManifest,
@@ -234,6 +235,58 @@ export function registerAgentStatusDerivationTests() {
}
export function registerRuntimeSettingsTests() {
it('shows the client version on the About settings page', async () => {
const invoke = vi.fn(async (command: string) => {
if (command === 'read_game_creator_app_config') {
return {
path: '/home/test/AppData/game-creator.config.json',
config: {
agentMode: 'codex_app_server',
llm: {
apiKey: '',
baseUrl: 'https://llm.example.test/v1',
model: 'gpt-about',
apiKind: 'openai_responses',
reasoningEffort: 'high',
stream: true,
webSearchEnabled: false,
contextWindowTokens: 128000,
autoCompactTokenLimit: 64000,
toolOutputTokenLimit: 12000,
requestTimeoutMs: 180000,
maxRetries: 2,
retryBackoffMs: 500,
},
agentLlm: {},
editorApi: {
baseUrl: 'http://127.0.0.1:8082',
apiKey: '',
},
},
};
}
throw new Error(`unexpected invoke ${command}`);
});
window.__TAURI__ = { core: { invoke } };
renderLauncherAt('/?launcher');
fireEvent.click(screen.getByRole('button', { name: '配置' }));
expect(
await screen.findByRole('dialog', { name: '运行时配置' }),
).not.toBeNull();
fireEvent.click(screen.getByRole('button', { name: /关于/ }));
expect(screen.getByText('Genarrative AI Game Creator')).not.toBeNull();
expect(
screen.getByTestId('runtime-settings-app-logo').getAttribute('src'),
).toContain('taonier-product-ip.png');
expect(screen.getByTestId('runtime-settings-app-version').textContent).toBe(
`v${APP_VERSION}`,
);
expect(screen.getByText('桌面客户端')).not.toBeNull();
});
it('keeps the Agent mode fixed to app-server and preserves its LLM config', async () => {
const invoke = vi.fn(
async (command: string, args?: Record<string, unknown>) => {
+1
View File
@@ -6,6 +6,7 @@
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"moduleDetection": "force",
"allowJs": false,
@@ -137,7 +137,7 @@ Supervisor 认领该回执后,由父 run 自己为每个原 delivery 逐一创
## 目标
在 Genarrative 内建设独立桌面 App:普通用户通过项目开发工作台中的陶泥儿对话、资源画布、运行状态和确认操作,让平台生成保存在本地的可运行 Web 游戏原型,并通过本地 HTTP server 预览;主窗口提供运行时配置入口,用于保存发布版 AppData / Tauri 配置目录里的 LLM 配置及受控开发者 External Editor 配置。普通客户素材画布使用平台登录态调用内部编辑器 API,不展示或要求填写画板 Base URL / API Key。任务明细、原始文件、命令日志和专业 Agent 调试控制只通过显式开发调试入口查看,不随普通客户端启动额外打开窗口。v1 的生成闭环仍以 Web 小游戏为主,同时允许用户打开已有 Godot 项目:用户选择的目录始终作为工作区根,`.agent/`、Session、Runtime、文件工具和外围资料都留在该根;客户端检查根目录及一层直接子目录中的普通文件 `project.godot`,将唯一命中的实际目录以工作区相对 `godotProjectRoot` 记录到 manifest。Agent 使用标准运行档继续修改,不创建 `game/``assets/``memory/``exports/` 平行目录;本期不扩展 Unity、Godot 内嵌预览、云同步或插件市场。
在 Genarrative 内建设独立桌面 App:普通用户通过项目开发工作台中的陶泥儿对话、资源画布、运行状态和确认操作,让平台生成保存在本地的可运行 Web 游戏原型,并通过本地 HTTP server 预览;主窗口提供运行时配置入口,用于保存发布版 AppData / Tauri 配置目录里的 LLM 配置及受控开发者 External Editor 配置,设置弹窗同时提供独立“关于”页并显示从客户端构建版本注入的版本号。普通客户素材画布使用平台登录态调用内部编辑器 API,不展示或要求填写画板 Base URL / API Key。任务明细、原始文件、命令日志和专业 Agent 调试控制只通过显式开发调试入口查看,不随普通客户端启动额外打开窗口。v1 的生成闭环仍以 Web 小游戏为主,同时允许用户打开已有 Godot 项目:用户选择的目录始终作为工作区根,`.agent/`、Session、Runtime、文件工具和外围资料都留在该根;客户端检查根目录及一层直接子目录中的普通文件 `project.godot`,将唯一命中的实际目录以工作区相对 `godotProjectRoot` 记录到 manifest。Agent 使用标准运行档继续修改,不创建 `game/``assets/``memory/``exports/` 平行目录;本期不扩展 Unity、Godot 内嵌预览、云同步或插件市场。
## 技术选择