Merge branch 'master' into codex/home-inspiration-gallery
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>) => {
|
||||
|
||||
@@ -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 内嵌预览、云同步或插件市场。
|
||||
|
||||
## 技术选择
|
||||
|
||||
|
||||
Reference in New Issue
Block a user