接入 AGC shell TS 资源 kind 边界

新增消费 Rust 生成绑定的未知值解析模块
迁移资源引用与画布引用入口并补充日志测试
更新逐项迁移清单与实施计划
This commit is contained in:
2026-09-15 18:00:34 +08:00
parent 20b0bf4dd7
commit 2befaaef9d
6 changed files with 93 additions and 4 deletions
@@ -0,0 +1,45 @@
import type { GameCreationAppAssetKind } from './generated/GameCreationAppAssetKind';
export type { GameCreationAppAssetKind } from './generated/GameCreationAppAssetKind';
export const GAME_CREATION_APP_ASSET_KINDS = [
'image',
'scene',
'character',
'character-animation',
'icon',
'icon-spritesheet',
'icon-spec',
'ui-design',
'ui-design-doc',
'publication-material',
'spec',
'video',
'audio',
'sound-effect',
'background-music',
'font',
'document',
'code',
'unknown',
] as const satisfies readonly GameCreationAppAssetKind[];
const KNOWN_ASSET_KINDS = new Set<string>(GAME_CREATION_APP_ASSET_KINDS);
export function parseGameCreationAppAssetKind(
raw: unknown,
context: string,
): GameCreationAppAssetKind {
if (typeof raw === 'string' && KNOWN_ASSET_KINDS.has(raw)) {
return raw as GameCreationAppAssetKind;
}
const rawValue = typeof raw === 'string' ? raw : String(raw);
if (rawValue !== 'unknown') {
console.warn('未知的 GameCreationApp 资源 kind,已收口为 unknown', {
rawKind: rawValue,
sourceContext: context,
});
}
return 'unknown';
}
@@ -10,6 +10,10 @@ import {
buildGameCreationAppAssetTagLibrary,
type GameCreationAppAssetTagLibraryEntry,
} from '../../../../../packages/shared/src/contracts/gameCreationAppAssetTagLibrary';
import {
type GameCreationAppAssetKind,
parseGameCreationAppAssetKind,
} from '../../contracts/assetKind';
export type ResourceReferenceSource =
| 'asset-picker'
@@ -20,7 +24,7 @@ export type ResourceReferenceSource =
export type ResourceReference = {
type: 'resource';
resourceId: string;
kind: string;
kind: GameCreationAppAssetKind;
mediaType: string;
label: string;
category: GameCreationAppAssetCategory;
@@ -98,7 +102,7 @@ export function resourceReferenceFromAsset(
return {
type: 'resource',
resourceId: asset.id,
kind: asset.kind,
kind: parseGameCreationAppAssetKind(asset.kind, 'resource-reference'),
mediaType: asset.mediaType,
label: resourceDisplayName(asset),
category: gameCreationAppAssetCategory(asset),
@@ -96,6 +96,7 @@ import {
isFloatingOverlayWheelEvent,
useImageCanvasFloatingOptionDismiss,
} from '../../../../../src/components/image-editor/useImageCanvasFloatingOptionDismiss';
import { parseGameCreationAppAssetKind } from '../../contracts/assetKind';
import { DesignWorkspacePanel } from '../../features/project-workspace/DesignWorkspacePanel';
import {
LocalGamePreviewFrame,
@@ -7226,9 +7227,11 @@ export default function ProjectDevelopmentView({
type: 'resource',
resourceId:
selectedResource.manifestAssetId!,
kind:
kind: parseGameCreationAppAssetKind(
selectedResource.subtype ||
selectedResource.category,
selectedResource.category,
'project-development.resource-reference',
),
mediaType: selectedResource.mediaType,
label: selectedResource.label,
category:
@@ -0,0 +1,28 @@
import { describe, expect, it, vi } from 'vitest';
import {
GAME_CREATION_APP_ASSET_KINDS,
parseGameCreationAppAssetKind,
} from '../src/contracts/assetKind';
describe('shell generated asset kind boundary', () => {
it('keeps the generated kind values aligned with the manifest vocabulary', () => {
expect(GAME_CREATION_APP_ASSET_KINDS).toContain('font');
expect(GAME_CREATION_APP_ASSET_KINDS).toContain('audio');
expect(GAME_CREATION_APP_ASSET_KINDS).toContain('sound-effect');
expect(GAME_CREATION_APP_ASSET_KINDS).toContain('background-music');
expect(GAME_CREATION_APP_ASSET_KINDS).toContain('unknown');
});
it('does not alias old values and records unknown input', () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
expect(parseGameCreationAppAssetKind('ui', 'manifest.asset.kind')).toBe(
'unknown',
);
expect(warn).toHaveBeenCalledWith(
'未知的 GameCreationApp 资源 kind,已收口为 unknown',
{ rawKind: 'ui', sourceContext: 'manifest.asset.kind' },
);
warn.mockRestore();
});
});
@@ -20,6 +20,7 @@
- `GameCreationAppAssetManifestEntry.kind` 改为 `GameCreationAppAssetKind`;manifest 反序列化未知值收口为 `Unknown`
- 上传内容推断的字体写入 `Font`,未知上传类型写入 `Unknown`;图集切片 manifest 写入 `Icon`
- shell TS 资源引用边界开始消费生成绑定,并为未知值保留原始值与上下文日志。
明确不修改:
@@ -210,3 +210,11 @@
- `resourceCanvasBottomToolbarModel.ts:243``art-spritesheet``:258``ui-prototype` 当前位于生成入口选项,需先确认该字段是否传入 manifest 登记;若只是 API/生成请求 kind,使用显式转换函数,不把旧值加入 manifest enum。
- `resourceProjectionModel.ts:326``uiDesignResourceBridge.ts:87` 是直接比较 manifest asset kind 的消费点,必须跟随生成绑定迁移到 enum。
- `SupervisorChatOnlyView.tsx``ProjectSupervisorView.tsx` 等仍直接从 `packages/shared` 导入 manifest 类型,需在删除旧文件前完成 shell 内导入收口。
## 已迁移的 TS 边界(增量)
- `src/contracts/assetKind.ts`:消费 Rust 生成的 `GameCreationAppAssetKind`,未知输入记录 `rawKind` / `sourceContext` 并返回 `unknown`,不做旧 alias 转换。
- `src/features/project-workspace/resourceReferences.ts`:资源引用 kind 改为生成枚举类型并通过 parser 收口。
- `src/view/project-development/index.tsx`:画布引用入口通过同一 parser 构造资源引用 kind。
其余 `packages/shared` import 和前端 manifest `kind: string` 字段仍未迁移,继续作为后续小切片,不在本次提交中伪装完成。