Files
Genarrative/apps/ai-game-creator-shell/src/features/project-workspace/projectCommandPolicy.ts
T
AIGameCreator App 759951ab12 继续拆分客户端工作区与 Agent 运行时模块
拆出项目工作区视图、命令策略、摘要命令与开发面板模块。

拆出 Runtime action、driver 与 protocol 的职责模块并保留稳定 facade。

保留测试模块、兼容重导出与原有可见性边界。

补充结构拆分决策、踩坑记录与实施计划验收结果。
2026-07-22 16:03:34 +08:00

141 lines
3.4 KiB
TypeScript

import {
GAME_CREATION_APP_COMMANDS,
type GameCreationAppCommandDescriptor,
} from '../../../../../packages/shared/src/contracts/gameCreationApp';
import type { PendingCommand } from '../../app/types';
import {
isAbsoluteProjectPath,
projectPathHasControlCharacter,
} from '../project-summary/projectSummary';
export function resolveChatProjectPath(
localProject: { projectPath: string } | null,
) {
const projectPath = localProject?.projectPath?.trim();
if (
!projectPath ||
!isAbsoluteProjectPath(projectPath) ||
projectPathHasControlCharacter(projectPath)
) {
return null;
}
return projectPath;
}
export function isAgentTraceFilePath(value: string) {
const path = value.trim();
return (
path === '.agent/run.latest.json' ||
(path.startsWith('.agent/runs/') && path.endsWith('.json'))
);
}
export function isRegisteredGameCreationCommandId(value: string) {
return GAME_CREATION_APP_COMMANDS.some((command) => command.id === value);
}
export function isProjectPolicyConfirmableCommandId(value: string) {
return [
'project.index',
'project.status',
'project.checkpoint',
'project.diff',
'project.restore',
'project.export_package',
'project.export_list',
'file.list',
'file.read',
'memory.read',
'memory.write',
'memory.delete',
'asset.register',
'asset.list',
'task.list',
'task.create',
'task.update',
'agent.run_status',
'agent.kill',
'agent.retry',
'agent.resume',
'agent.delegate',
'agent.spawn_isolated',
'agent.schedule_ready',
'agent.audit',
'agent.trace_read',
'preview.status',
'preview.start',
'preview.validate',
'preview.open',
'preview.stop',
'canvas.project_sync',
'canvas.asset_import',
'canvas.asset_generate',
'canvas.export_import',
'conversation.read',
'conversation.write',
].includes(value);
}
export function isSafeCanvasProjectId(value: string) {
return !!value.trim() && !projectPathHasControlCharacter(value);
}
export function isSafeCheckpointId(value: string) {
const checkpointId = value.trim();
return (
!!checkpointId &&
!projectPathHasControlCharacter(checkpointId) &&
!checkpointId.includes('/') &&
!checkpointId.includes('\\') &&
!checkpointId.includes('..')
);
}
export function needsInitializedChatProject(
commandId: GameCreationAppCommandDescriptor['id'],
) {
return [
'asset.upload',
'asset.register',
'agent.delegate',
'agent.kill',
'agent.retry',
'agent.resume',
'command.run_limited',
'game.generate_draft',
'game.run_local',
'file.list',
'file.read',
'project.checkpoint',
'project.export_package',
'project.export_list',
'project.restore',
'project.policy_write',
'preview.open',
'preview.start',
'canvas.project_sync',
'canvas.asset_import',
'canvas.asset_generate',
'canvas.export_import',
'memory.read',
'memory.write',
'memory.delete',
'conversation.read',
'conversation.write',
].includes(commandId);
}
export function resolvePendingCommandProjectPath(
command: PendingCommand,
localProject: { projectPath: string } | null,
draftProjectPath: string,
) {
if (command.id === 'project.create') {
return command.projectPath;
}
if (needsInitializedChatProject(command.id)) {
return resolveChatProjectPath(localProject) ?? draftProjectPath;
}
return draftProjectPath;
}