补充AI游戏创作草稿快捷入口
新增灵感草稿入口,仅填入创作需求不触发生成 新增预览和Agent状态权限确认草稿入口 补充主窗口草稿入口测试覆盖 同步AI游戏创作App文档和共享决策记录
This commit is contained in:
@@ -9398,6 +9398,16 @@ export function App() {
|
||||
</div>
|
||||
</header>
|
||||
<div className="chat-quick-actions" aria-label="预览快捷操作">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
prepareChatCommandDraft(
|
||||
'像素风厨房弹幕小游戏:玩家用方向键躲避飞来的食材,收集调料加分,60 秒内尽量高分,失败后可一键重开。',
|
||||
)
|
||||
}
|
||||
>
|
||||
灵感草稿
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!localProject}
|
||||
@@ -9453,6 +9463,22 @@ export function App() {
|
||||
>
|
||||
任务
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!localProject}
|
||||
onClick={() => prepareChatCommandDraft('/policy-confirm preview.start')}
|
||||
>
|
||||
预览确认
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!localProject}
|
||||
onClick={() =>
|
||||
prepareChatCommandDraft('/policy-confirm agent.run_status')
|
||||
}
|
||||
>
|
||||
Agent确认
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!localProject}
|
||||
|
||||
@@ -200,6 +200,10 @@ describe('AI 游戏创作 App 界面边界', () => {
|
||||
expect(screen.getByRole('button', { name: '配置' })).not.toBeNull();
|
||||
expect(screen.getByRole('button', { name: 'LLM状态' })).not.toBeNull();
|
||||
expect(screen.getByRole('button', { name: '显示目录' })).not.toBeNull();
|
||||
expect(
|
||||
(screen.getByRole('button', { name: '灵感草稿' }) as HTMLButtonElement)
|
||||
.disabled,
|
||||
).toBe(false);
|
||||
expect(
|
||||
(screen.getByRole('button', { name: '项目状态' }) as HTMLButtonElement)
|
||||
.disabled,
|
||||
@@ -235,6 +239,14 @@ describe('AI 游戏创作 App 界面边界', () => {
|
||||
(screen.getByRole('button', { name: '任务' }) as HTMLButtonElement)
|
||||
.disabled,
|
||||
).toBe(true);
|
||||
expect(
|
||||
(screen.getByRole('button', { name: '预览确认' }) as HTMLButtonElement)
|
||||
.disabled,
|
||||
).toBe(true);
|
||||
expect(
|
||||
(screen.getByRole('button', { name: 'Agent确认' }) as HTMLButtonElement)
|
||||
.disabled,
|
||||
).toBe(true);
|
||||
expect(
|
||||
(screen.getByRole('button', { name: 'Trace' }) as HTMLButtonElement)
|
||||
.disabled,
|
||||
@@ -352,6 +364,12 @@ describe('AI 游戏创作 App 界面边界', () => {
|
||||
).toBe(true);
|
||||
fireEvent.click(screen.getByRole('button', { name: '打开画板' }));
|
||||
expect(composerInput).toHaveProperty('value', '/canvas ');
|
||||
fireEvent.click(screen.getByRole('button', { name: '灵感草稿' }));
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
'像素风厨房弹幕小游戏:玩家用方向键躲避飞来的食材,收集调料加分,60 秒内尽量高分,失败后可一键重开。',
|
||||
);
|
||||
expect(screen.queryByText('game.generate_draft')).toBeNull();
|
||||
fireEvent.click(screen.getByRole('button', { name: '白名单' }));
|
||||
expect(await screen.findByText(/可运行受限命令:/)).not.toBeNull();
|
||||
expect(screen.getByRole('button', { name: '切换项目' })).not.toBeNull();
|
||||
@@ -1891,6 +1909,22 @@ describe('AI 游戏创作 App 界面边界', () => {
|
||||
expect(
|
||||
await screen.findByText(/策略:\.agent\/policy\.json/),
|
||||
).not.toBeNull();
|
||||
const composerInput = screen.getByLabelText('创作想法');
|
||||
fireEvent.click(screen.getByRole('button', { name: '预览确认' }));
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
'/policy-confirm preview.start',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Agent确认' }));
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
'/policy-confirm agent.run_status',
|
||||
);
|
||||
expect(screen.queryByText('project.policy_write')).toBeNull();
|
||||
expect(invoke).not.toHaveBeenCalledWith(
|
||||
'write_project_permission_policy',
|
||||
expect.anything(),
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '审计' }));
|
||||
expect(await screen.findByText(/Agent v1 审计:/)).not.toBeNull();
|
||||
@@ -1904,7 +1938,6 @@ describe('AI 游戏创作 App 界面边界', () => {
|
||||
'uploaded · text/plain · uploaded',
|
||||
),
|
||||
).not.toBeNull();
|
||||
const composerInput = screen.getByLabelText('创作想法');
|
||||
fireEvent.click(screen.getByRole('button', { name: '打开画板' }));
|
||||
expect(composerInput).toHaveProperty('value', '/canvas ');
|
||||
await waitFor(() => expect(document.activeElement).toBe(composerInput));
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
- 背景:AI 游戏创作 App 已有 Godcoder 式本地工程护栏、项目黑板、角色私有记忆、manifest 和 run trace;新增结构化对话记录、agent 状态列表和单 agent 对话入口时,需要避免引入平行状态源或提前承诺后台 runner 能力。
|
||||
- 决策:v1 结构化对话记录统一使用本地 `.agent/conversations/` append-only JSONL。普通聊天写 `.agent/conversations/project.jsonl`;从 agent 状态列表进入单个 agent 后,用户消息、agent 回复、工具建议和错误只写对应 `.agent/conversations/agents/<agentId>.jsonl`。Agent 状态列表从 `.agent/manifest.json` 的任务 / 角色清单和 `.agent/run.latest.json` / `.agent/runs/<runId>.json` 的 step、taskGraph、passPlans、lifecycleStatus 派生,并把 `taskGraph.tasks` 的任务状态与 active / carry-over / ready 编排标记显示在主窗口和单 agent 对话入口中;单 agent 最近证据里的安全相对输入 / 输出路径只填入 `/read <path>` 草稿,仍由用户发送并走既有 `file.read` / `agent.trace_read` 权限流。不新增独立状态数据库。项目黑板和角色私有记忆继续只保存稳定摘要,不承载原始对话流水。
|
||||
- 补充:App 启动先进入独立启动器窗口;用户选择工作区后,Tauri 关闭启动器并打开主窗口,主窗口读取该工作区的主 conversation、manifest 和 run trace。启动器“新建项目”先调用 `init_local_game_project` 初始化成功,默认项目名取目标文件夹名,再写最近项目并打开主窗口;遇到非空目录时先弹确认,取消或初始化失败则不打开主窗口、不写最近项目。最近工作区只保存在本机 WebView storage,可单项移除或清空,不进入项目文件或共享记忆;已初始化项目优先显示 manifest 项目名并保留路径副信息,`.agent/run.latest.json` 可读时显示最近 run 状态。最近项目路径缺失、不是目录、缺少可读 `.agent/manifest.json` 或检查失败时禁用打开,刷新只重新执行只读检查;“显示”只用系统文件管理器打开已确认存在的本地目录,未初始化但存在的目录也可显示,避免把历史路径误当新项目重建。
|
||||
- 补充:主窗口“显示目录”复用同一只读目录打开能力,只打开当前本地项目目录,不初始化项目、不写项目文件、不切换工作区;主窗口头部只读显示 manifest 项目名、项目路径、最近 `.agent/run.latest.json` 的 run 状态摘要和当前预览状态,并通过“刷新状态”重新读取同一 trace,不新增状态数据库。最近项目资产入口只读展示 localPath、kind、mediaType 和 source.kind,点击仍走原 `file.read` 权限流;旁边的“读取命令”只填入 `/read <path>` 草稿,不直接读取文件或绕过权限。主窗口“记到黑板”“覆盖黑板”“清空黑板”只填入项目黑板相关 `/remember`、`/memory-set` 和 `/forget-memory` 草稿,项目黑板写入或删除仍走聊天确认;Agent 状态栏的 output / activity / context bundle 入口也只填入 `/read` 草稿,不直接读取 run 辅助文件。
|
||||
- 补充:主窗口“显示目录”复用同一只读目录打开能力,只打开当前本地项目目录,不初始化项目、不写项目文件、不切换工作区;主窗口头部只读显示 manifest 项目名、项目路径、最近 `.agent/run.latest.json` 的 run 状态摘要和当前预览状态,并通过“刷新状态”重新读取同一 trace,不新增状态数据库。最近项目资产入口只读展示 localPath、kind、mediaType 和 source.kind,点击仍走原 `file.read` 权限流;旁边的“读取命令”只填入 `/read <path>` 草稿,不直接读取文件或绕过权限。主窗口“记到黑板”“覆盖黑板”“清空黑板”只填入项目黑板相关 `/remember`、`/memory-set` 和 `/forget-memory` 草稿,项目黑板写入或删除仍走聊天确认;Agent 状态栏的 output / activity / context bundle 入口也只填入 `/read` 草稿,不直接读取 run 辅助文件;灵感草稿和权限策略快捷入口同样只填入输入框,不提交、不写 `.agent/policy.json`、不调用 LLM。
|
||||
- 补充:启动器和主窗口共用同一个运行时配置弹窗,配置只读写 Tauri 应用配置目录中的 `game-creator.config.json`,不写入项目文件或对话历史。
|
||||
- 补充:启动器“打开”只进入已初始化且 `.agent/manifest.json` 可读的 AI 游戏项目;路径不存在、不是文件夹或只是普通文件夹时不打开主窗口、不创建目录,用户需要创建或初始化时走“新建项目”。
|
||||
- 影响范围:`apps/ai-game-creator-shell` 的主窗口 agent 状态列表、单 agent 对话入口、本地项目文件结构、共享契约和 AI 游戏创作 App 实施计划。
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user