From c5200c7d45007aee0bf7298a32248fb3e7d13879 Mon Sep 17 00:00:00 2001 From: kdletters Date: Mon, 31 Aug 2026 14:10:44 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E8=A1=A5=E9=BD=90=E5=85=B1=E4=BA=AB=20UI?= =?UTF-8?q?=20=E7=BB=84=E4=BB=B6=E5=BA=93=E4=B8=8E=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E9=A1=B5=E4=BA=A4=E4=BA=92=20(#202)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 变更内容 - 新增基于 shadcn open-code 模式的共享 UI canonical 组件、样式与导出。 - 新增 `/components` 共享组件展示页,并覆盖平台组件、Token、状态和移动端布局。 - 补齐平台展示页的筛选、排序、上传预览、标签、开关和异步状态交互。 - 修复排序导致预览主题变化、筛选弹窗误关闭和入口状态不更新的问题。 - 同步网站与客户端构建别名、依赖、路由测试和项目文档。 ## 验证 - `npm run test -- src/components/shared-components/SharedComponentsShowcasePage.test.tsx` - `npm run typecheck` - `npm run check:encoding` - `npm run build:raw` - `git diff --check` - pre-push 门禁通过 Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/202 Co-authored-by: kdletters Co-committed-by: kdletters --- AGENTS.md | 1 + .../src/components/AdminEditorAssetMedia.tsx | 2 +- ...ent-runtime-deterministic-playable-e2e.mjs | 3 +- .../harness/app-data.mjs | 19 +- .../deterministic-lane-defense-provider.mjs | 48 +- apps/ai-game-creator-shell/src/styles.css | 1 + apps/ai-game-creator-shell/tsconfig.json | 17 +- apps/ai-game-creator-shell/vite.config.ts | 40 + components.json | 19 + docs/README.md | 1 + .../shared-memory/decision-log.md | 65 +- .../shared-memory/team-conventions.md | 1 + ...端架构】共享基础组件库与展示页-2026-08-26.md | 57 + package-lock.json | 962 ++++++++++++- packages/shared/package.json | 21 +- .../src/components/PlatformActionButton.tsx | 102 ++ .../components/PlatformAsyncStatePanel.tsx | 37 + .../PlatformBackActionButton.test.tsx | 36 + .../components/PlatformBackActionButton.tsx | 53 + .../shared/src/components/PlatformBadge.tsx | 5 + .../src/components/PlatformEmptyState.tsx | 128 ++ .../src/components/PlatformFieldLabel.tsx | 44 + .../src/components/PlatformFilterToolbar.tsx | 112 ++ .../src/components/PlatformIconBadge.tsx | 92 ++ .../src/components/PlatformIconButton.tsx | 152 ++ .../src/components/PlatformInfoBlock.tsx | 100 ++ .../shared/src/components/PlatformModal.tsx | 2 + .../components/PlatformNavigableListItem.tsx | 88 ++ .../src/components/PlatformPillBadge.tsx | 45 + .../src/components/PlatformProgressBar.tsx | 90 ++ .../components/PlatformRuntimeStatusToast.tsx | 103 ++ .../src/components/PlatformSegmentedTabs.tsx | 248 ++++ .../src/components/PlatformStatGrid.tsx | 158 +++ .../shared/src/components/PlatformStatus.tsx | 5 + .../src/components/PlatformStatusMessage.tsx | 113 ++ .../src/components/PlatformSubpanel.tsx | 223 +++ .../src/components/PlatformTextField.tsx | 184 +++ .../src/components/PlatformToggleRow.test.tsx | 79 ++ .../src/components/PlatformToggleRow.tsx | 134 ++ packages/shared/src/components/account.ts | 5 + packages/shared/src/components/index.ts | 230 +++ .../components/platformActionButtonModel.ts | 134 ++ .../components/platformComponents.test.tsx | 108 ++ .../src/components/platformPillBadgeModel.ts | 68 + packages/shared/src/components/styles.css | 1259 +++++++++++++++++ packages/shared/src/components/ui.test.tsx | 209 +++ packages/shared/src/components/ui.tsx | 591 ++++++++ packages/shared/src/components/ui/badge.tsx | 52 + .../shared/src/components/ui/button.test.tsx | 45 + packages/shared/src/components/ui/button.tsx | 97 ++ packages/shared/src/components/ui/card.tsx | 73 + .../shared/src/components/ui/checkbox.tsx | 21 + packages/shared/src/components/ui/dialog.tsx | 163 +++ packages/shared/src/components/ui/index.ts | 48 + packages/shared/src/components/ui/input.tsx | 42 + packages/shared/src/components/ui/label.tsx | 21 + .../src/components/ui/primitives.test.tsx | 38 + .../shared/src/components/ui/skeleton.tsx | 16 + packages/shared/src/components/ui/switch.tsx | 41 + packages/shared/src/components/ui/table.tsx | 112 ++ .../shared/src/components/ui/tabs.test.tsx | 30 + packages/shared/src/components/ui/tabs.tsx | 73 + .../shared/src/components/ui/textarea.tsx | 29 + packages/shared/src/index.ts | 3 +- packages/shared/src/lib/index.ts | 1 + packages/shared/src/lib/utils.ts | 7 + src/active-main.tsx | 2 +- src/components/CustomWorldEntityCatalog.tsx | 20 +- src/components/auth/AccountModal.tsx | 18 +- src/components/auth/BindPhoneScreen.tsx | 12 +- src/components/auth/LoginScreen.tsx | 14 +- .../BarkBattlePreviewCard.tsx | 3 +- .../common/PlatformActionButton.tsx | 97 +- .../common/PlatformAsyncStatePanel.tsx | 39 +- .../common/PlatformBackActionButton.tsx | 62 +- src/components/common/PlatformEmptyState.tsx | 129 +- src/components/common/PlatformFieldLabel.tsx | 52 +- .../common/PlatformFilterToolbar.tsx | 113 +- src/components/common/PlatformIconBadge.tsx | 92 +- src/components/common/PlatformIconButton.tsx | 162 +-- src/components/common/PlatformInfoBlock.tsx | 103 +- .../common/PlatformNavigableListItem.tsx | 93 +- src/components/common/PlatformPillBadge.tsx | 46 +- src/components/common/PlatformProgressBar.tsx | 93 +- .../common/PlatformRuntimeStatusToast.tsx | 110 +- .../common/PlatformSegmentedTabs.tsx | 249 +--- src/components/common/PlatformStatGrid.tsx | 160 +-- .../common/PlatformStatusMessage.tsx | 115 +- src/components/common/PlatformSubpanel.tsx | 232 +-- src/components/common/PlatformTextField.tsx | 192 +-- src/components/common/PlatformToggleRow.tsx | 138 +- .../common/platformActionButtonModel.ts | 140 +- .../common/platformPillBadgeModel.ts | 73 +- .../creation-agent/CreationAgentWorkspace.tsx | 24 +- .../CustomWorldCreationHub.tsx | 14 +- .../BabyObjectMatchWorkspace.tsx | 16 +- .../match3d-result/Match3DResultView.tsx | 32 +- .../puzzle-result/PuzzleResultView.tsx | 32 +- .../RpgCreationAssetDebugPanel.tsx | 8 +- .../RpgCreationResultActionBar.tsx | 12 +- .../RpgCreationResultViewImpl.tsx | 6 +- src/components/rpg-entry/RpgEntryHomeView.tsx | 14 +- .../SharedComponentsShowcasePage.test.tsx | 99 ++ .../SharedComponentsShowcasePage.tsx | 809 +++++++++++ .../sharedComponentsShowcase.css | 244 ++++ .../SquareHoleResultView.tsx | 22 +- .../VisualNovelResultView.tsx | 31 +- src/index.css | 1 + src/routing/activeAppRoutes.test.ts | 14 + src/routing/activeAppRoutes.tsx | 31 +- tsconfig.json | 17 +- vite.config.ts | 40 + vitest.config.ts | 1 + 113 files changed, 8576 insertions(+), 2556 deletions(-) create mode 100644 components.json create mode 100644 docs/technical/【前端架构】共享基础组件库与展示页-2026-08-26.md create mode 100644 packages/shared/src/components/PlatformActionButton.tsx create mode 100644 packages/shared/src/components/PlatformAsyncStatePanel.tsx create mode 100644 packages/shared/src/components/PlatformBackActionButton.test.tsx create mode 100644 packages/shared/src/components/PlatformBackActionButton.tsx create mode 100644 packages/shared/src/components/PlatformBadge.tsx create mode 100644 packages/shared/src/components/PlatformEmptyState.tsx create mode 100644 packages/shared/src/components/PlatformFieldLabel.tsx create mode 100644 packages/shared/src/components/PlatformFilterToolbar.tsx create mode 100644 packages/shared/src/components/PlatformIconBadge.tsx create mode 100644 packages/shared/src/components/PlatformIconButton.tsx create mode 100644 packages/shared/src/components/PlatformInfoBlock.tsx create mode 100644 packages/shared/src/components/PlatformModal.tsx create mode 100644 packages/shared/src/components/PlatformNavigableListItem.tsx create mode 100644 packages/shared/src/components/PlatformPillBadge.tsx create mode 100644 packages/shared/src/components/PlatformProgressBar.tsx create mode 100644 packages/shared/src/components/PlatformRuntimeStatusToast.tsx create mode 100644 packages/shared/src/components/PlatformSegmentedTabs.tsx create mode 100644 packages/shared/src/components/PlatformStatGrid.tsx create mode 100644 packages/shared/src/components/PlatformStatus.tsx create mode 100644 packages/shared/src/components/PlatformStatusMessage.tsx create mode 100644 packages/shared/src/components/PlatformSubpanel.tsx create mode 100644 packages/shared/src/components/PlatformTextField.tsx create mode 100644 packages/shared/src/components/PlatformToggleRow.test.tsx create mode 100644 packages/shared/src/components/PlatformToggleRow.tsx create mode 100644 packages/shared/src/components/account.ts create mode 100644 packages/shared/src/components/index.ts create mode 100644 packages/shared/src/components/platformActionButtonModel.ts create mode 100644 packages/shared/src/components/platformComponents.test.tsx create mode 100644 packages/shared/src/components/platformPillBadgeModel.ts create mode 100644 packages/shared/src/components/styles.css create mode 100644 packages/shared/src/components/ui.test.tsx create mode 100644 packages/shared/src/components/ui.tsx create mode 100644 packages/shared/src/components/ui/badge.tsx create mode 100644 packages/shared/src/components/ui/button.test.tsx create mode 100644 packages/shared/src/components/ui/button.tsx create mode 100644 packages/shared/src/components/ui/card.tsx create mode 100644 packages/shared/src/components/ui/checkbox.tsx create mode 100644 packages/shared/src/components/ui/dialog.tsx create mode 100644 packages/shared/src/components/ui/index.ts create mode 100644 packages/shared/src/components/ui/input.tsx create mode 100644 packages/shared/src/components/ui/label.tsx create mode 100644 packages/shared/src/components/ui/primitives.test.tsx create mode 100644 packages/shared/src/components/ui/skeleton.tsx create mode 100644 packages/shared/src/components/ui/switch.tsx create mode 100644 packages/shared/src/components/ui/table.tsx create mode 100644 packages/shared/src/components/ui/tabs.test.tsx create mode 100644 packages/shared/src/components/ui/tabs.tsx create mode 100644 packages/shared/src/components/ui/textarea.tsx create mode 100644 packages/shared/src/lib/index.ts create mode 100644 packages/shared/src/lib/utils.ts create mode 100644 src/components/shared-components/SharedComponentsShowcasePage.test.tsx create mode 100644 src/components/shared-components/SharedComponentsShowcasePage.tsx create mode 100644 src/components/shared-components/sharedComponentsShowcase.css diff --git a/AGENTS.md b/AGENTS.md index 4ba512832..7b4ddcfdd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -27,6 +27,7 @@ - 后续新增 Markdown 文档文件名必须以分类标签开头,格式为 `【标签名】中文标题-日期.md`;历史文档不要求批量重命名,除非本次任务明确涉及。 - 工程修改要同步更新对应 `docs/` 文档;产生长期有效的架构约定、接口变化、排障经验、开发流程或协作规则时,同步更新 `docs/project-memory/shared-memory/`。 - 默认保持系统简洁:优先复用、修改、扩展现有系统、页面和公共组件,不新建平行系统或平行页面。 +- UI 开发优先复用现有公共组件;发现跨页面或跨端重复的视觉/交互模式时,先抽取到 `packages/shared` 共享组件库并让现有页面迁移使用,禁止在业务页复制同类 UI。共享组件只承载通用表现与交互,不下沉领域规则、后端副作用或正式业务状态。 - 对已明确退役且不存在现役调用方、公开契约、持久化数据、活跃实例或迁移要求的对象,坚持“四不写”: 1. 不写历史兼容代码。 2. 不写用于维持退役行为的防御性兼容测试。 diff --git a/apps/admin-web/src/components/AdminEditorAssetMedia.tsx b/apps/admin-web/src/components/AdminEditorAssetMedia.tsx index 36c13586f..ca06149f2 100644 --- a/apps/admin-web/src/components/AdminEditorAssetMedia.tsx +++ b/apps/admin-web/src/components/AdminEditorAssetMedia.tsx @@ -736,7 +736,7 @@ function isAdminImageSequenceFrameUrlUsable( ): cached is AdminImageSequenceFrameCacheEntry { return Boolean( cached?.resolvedUrl && - (cached.expiresAtMs === null || cached.expiresAtMs > Date.now()), + (cached.expiresAtMs === null || cached.expiresAtMs > Date.now()), ); } diff --git a/apps/ai-game-creator-shell/scripts/agent-runtime-deterministic-playable-e2e.mjs b/apps/ai-game-creator-shell/scripts/agent-runtime-deterministic-playable-e2e.mjs index 8bf357203..ba8b9b3eb 100644 --- a/apps/ai-game-creator-shell/scripts/agent-runtime-deterministic-playable-e2e.mjs +++ b/apps/ai-game-creator-shell/scripts/agent-runtime-deterministic-playable-e2e.mjs @@ -26,8 +26,7 @@ const wrapperSuite = const configFileName = 'game-creator.config.json'; const configSentinelName = '.deterministic-provider-e2e.json'; const configSentinelSchema = 'genarrative-deterministic-provider-e2e-config.v1'; -const platformSessionFixtureEnv = - 'GENARRATIVE_AGC_PLATFORM_SESSION_FIXTURE'; +const platformSessionFixtureEnv = 'GENARRATIVE_AGC_PLATFORM_SESSION_FIXTURE'; const platformSessionFixtureName = '.deterministic-platform-session.json'; const platformSessionFixtureSchema = 'genarrative-agc-platform-session-fixture.v1'; diff --git a/apps/ai-game-creator-shell/scripts/agent-runtime-real-e2e/harness/app-data.mjs b/apps/ai-game-creator-shell/scripts/agent-runtime-real-e2e/harness/app-data.mjs index 389fef24d..f283ecf8e 100644 --- a/apps/ai-game-creator-shell/scripts/agent-runtime-real-e2e/harness/app-data.mjs +++ b/apps/ai-game-creator-shell/scripts/agent-runtime-real-e2e/harness/app-data.mjs @@ -100,8 +100,7 @@ import { appendBounded, runProcess } from './process.mjs'; import { decodeUtf8Fatal, isIsolatedRunnerSuite } from './reporting.mjs'; import { killRunnerOnce, readRunnerStatus, runnerBootId } from './runtime.mjs'; -const platformSessionFixtureEnv = - 'GENARRATIVE_AGC_PLATFORM_SESSION_FIXTURE'; +const platformSessionFixtureEnv = 'GENARRATIVE_AGC_PLATFORM_SESSION_FIXTURE'; const platformSessionFixtureMaxBytes = 16 * 1024; const isolatedPlatformSessionFixtureName = '.deterministic-platform-session.json'; @@ -538,7 +537,9 @@ async function readPlatformSessionFixtureForIsolatedSuite(sourceConfigDir) { ); let fixture; try { - fixture = JSON.parse(decodeUtf8Fatal(bytes, 'platform-session-fixture-invalid-utf8')); + fixture = JSON.parse( + decodeUtf8Fatal(bytes, 'platform-session-fixture-invalid-utf8'), + ); } catch (error) { throw codedError( 'supervisor-autonomous-playable-platform-session-fixture-invalid', @@ -577,8 +578,12 @@ async function installPlatformSessionFixtureIntoIsolatedAppData( appDataDir, ) { if (!isSupervisorAutonomousPlayableLaneDefenseSuite()) return; - const source = await readPlatformSessionFixtureForIsolatedSuite(sourceConfigDir); - const isolatedPath = path.join(appDataDir, isolatedPlatformSessionFixtureName); + const source = + await readPlatformSessionFixtureForIsolatedSuite(sourceConfigDir); + const isolatedPath = path.join( + appDataDir, + isolatedPlatformSessionFixtureName, + ); await fs.copyFile( source.sourcePath, isolatedPath, @@ -609,9 +614,7 @@ async function installPlatformSessionFixtureIntoIsolatedAppData( absolutePathVariants(source.sourcePath, isolatedPath), ); const previousLeakCount = state.transcriptScanner?.count ?? 0; - state.secrets = [ - ...new Set([...state.secrets, source.fixture.accessToken]), - ]; + state.secrets = [...new Set([...state.secrets, source.fixture.accessToken])]; rebuildSupervisorSwarmTranscriptScanner(); state.transcriptScanner.count = previousLeakCount; } diff --git a/apps/ai-game-creator-shell/scripts/deterministic-lane-defense-provider.mjs b/apps/ai-game-creator-shell/scripts/deterministic-lane-defense-provider.mjs index 8f81447ac..fed45aa02 100644 --- a/apps/ai-game-creator-shell/scripts/deterministic-lane-defense-provider.mjs +++ b/apps/ai-game-creator-shell/scripts/deterministic-lane-defense-provider.mjs @@ -990,7 +990,10 @@ export function createDeterministicLaneDefenseRouter({ } function recordReadyTaskRun(agentId, runId) { - if (!relaxedAutonomous && !deterministicManifestReadyAgentIds.includes(agentId)) { + if ( + !relaxedAutonomous && + !deterministicManifestReadyAgentIds.includes(agentId) + ) { throw providerError(`provider-ready-agent-unsupported:${agentId}`); } const existingRunId = readyTaskRunIdsByAgent.get(agentId); @@ -1405,14 +1408,10 @@ export function createDeterministicLaneDefenseRouter({ ]); } if (tools.has(runtimeFunction('task.list'))) { - const calls = [ - nativeAction('task.list', '查看并行任务当前状态', {}), - ]; + const calls = [nativeAction('task.list', '查看并行任务当前状态', {})]; if (tools.has(runtimeFunction('agent.run_status'))) { stats.runStatusCount += 1; - calls.push( - runStatusCall('读取并行任务的最新运行状态'), - ); + calls.push(runStatusCall('读取并行任务的最新运行状态')); } return callsResponse('project-supervisor', tools, calls); } @@ -1751,7 +1750,11 @@ export function createDeterministicLaneDefenseRouter({ stats.sourceWriteCount += 1; stats.manifestReadyTaskFileWriteCount += 1; return readyCallsResponse(agentId, runId, tools, [ - fileWriteCall(path, content, `重试写入 ${path} 并交给 Runtime 收束门验证`), + fileWriteCall( + path, + content, + `重试写入 ${path} 并交给 Runtime 收束门验证`, + ), ]); } // Runtime validates fixed owner artifacts after the owner responds. Once @@ -1769,12 +1772,7 @@ export function createDeterministicLaneDefenseRouter({ if (calls.some((call) => call.name === 'respond_to_user')) { recordReadyTaskCompletion(agentId, runId); } - return readyCallsResponse( - agentId, - runId, - tools, - calls, - ); + return readyCallsResponse(agentId, runId, tools, calls); } const recovery = runData.get(runId)?.writerRecovery ?? null; const observations = observationContext(context); @@ -2195,13 +2193,18 @@ export function createDeterministicLaneDefenseRouter({ if (finalReplyRuns.has(key)) { throw providerError('provider-duplicate-final-reply-request'); } - if (!relaxedAutonomous && + if ( + !relaxedAutonomous && !context.includes('给用户一个正常中文回复') && !context.includes('给开发者一个正常中文回复') ) { throw providerError('provider-unexpected-text-request'); } - if (!relaxedAutonomous && identity.agentId === 'project-supervisor' && parentStage !== 'done') { + if ( + !relaxedAutonomous && + identity.agentId === 'project-supervisor' && + parentStage !== 'done' + ) { throw providerError('provider-parent-final-reply-before-acceptance'); } finalReplyRuns.add(key); @@ -2586,8 +2589,7 @@ function createDeterministicCanvasFixture(apiKey) { } if ( request.method === 'POST' && - canonicalPath === - '/api/external/v1/editor/icon-spritesheets/generations' + canonicalPath === '/api/external/v1/editor/icon-spritesheets/generations' ) { const idempotencyKey = request.headers['idempotency-key']; if ( @@ -2906,7 +2908,9 @@ function createDeterministicCanvasFixture(apiKey) { if ( request.method === 'POST' && - canonicalPath?.match(/^\/api\/external\/v1\/editor\/projects\/[^/]+\/resources$/) + canonicalPath?.match( + /^\/api\/external\/v1\/editor\/projects\/[^/]+\/resources$/, + ) ) { const body = await readJsonBody(request); const objectKey = @@ -2959,7 +2963,11 @@ export async function startDeterministicLaneDefenseProvider({ relaxed = false, fallbackPorts = DEFAULT_FALLBACK_PORTS, } = {}) { - const router = createDeterministicLaneDefenseRouter({ apiKey, model, relaxed }); + const router = createDeterministicLaneDefenseRouter({ + apiKey, + model, + relaxed, + }); const canvasFixture = createDeterministicCanvasFixture(apiKey); const sockets = new Set(); let stopped = false; diff --git a/apps/ai-game-creator-shell/src/styles.css b/apps/ai-game-creator-shell/src/styles.css index 0c9984c75..b150722b5 100644 --- a/apps/ai-game-creator-shell/src/styles.css +++ b/apps/ai-game-creator-shell/src/styles.css @@ -1,5 +1,6 @@ @import 'tailwindcss'; @source '../../../packages/shared/src/components'; +@import '@genarrative/shared/styles.css'; @import '../../../packages/shared/src/theme.css'; :root { diff --git a/apps/ai-game-creator-shell/tsconfig.json b/apps/ai-game-creator-shell/tsconfig.json index 894821755..e18485909 100644 --- a/apps/ai-game-creator-shell/tsconfig.json +++ b/apps/ai-game-creator-shell/tsconfig.json @@ -22,7 +22,22 @@ ], "@genarrative/image-canvas-react": [ "packages/image-canvas-react/src/index.ts" - ] + ], + "@genarrative/shared": ["packages/shared/src/index.ts"], + "@genarrative/shared/components": [ + "packages/shared/src/components/index.ts" + ], + "@genarrative/shared/components/account": [ + "packages/shared/src/components/account.ts" + ], + "@genarrative/shared/components/ui": [ + "packages/shared/src/components/ui/index.ts" + ], + "@genarrative/shared/components/ui/*": [ + "packages/shared/src/components/ui/*" + ], + "@genarrative/shared/lib/*": ["packages/shared/src/lib/*"], + "@genarrative/shared/lib": ["packages/shared/src/lib/index.ts"] } }, "include": ["src", "vite.config.ts"] diff --git a/apps/ai-game-creator-shell/vite.config.ts b/apps/ai-game-creator-shell/vite.config.ts index 8f784f2a0..71b012d81 100644 --- a/apps/ai-game-creator-shell/vite.config.ts +++ b/apps/ai-game-creator-shell/vite.config.ts @@ -105,6 +105,46 @@ export default defineConfig({ 'packages/image-canvas-react/src/index.ts', ), }, + { + find: '@genarrative/shared/styles.css', + replacement: resolve( + repoRoot, + 'packages/shared/src/components/styles.css', + ), + }, + { + find: '@genarrative/shared/theme.css', + replacement: resolve(repoRoot, 'packages/shared/src/theme.css'), + }, + { + find: '@genarrative/shared/components/ui', + replacement: resolve( + repoRoot, + 'packages/shared/src/components/ui/index.ts', + ), + }, + { + find: '@genarrative/shared/lib', + replacement: resolve(repoRoot, 'packages/shared/src/lib'), + }, + { + find: '@genarrative/shared/components/account', + replacement: resolve( + repoRoot, + 'packages/shared/src/components/account.ts', + ), + }, + { + find: '@genarrative/shared/components', + replacement: resolve( + repoRoot, + 'packages/shared/src/components/index.ts', + ), + }, + { + find: '@genarrative/shared', + replacement: resolve(repoRoot, 'packages/shared/src/index.ts'), + }, ], dedupe: ['react', 'react-dom'], }, diff --git a/components.json b/components.json new file mode 100644 index 000000000..035330aed --- /dev/null +++ b/components.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/index.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@genarrative/shared/components", + "ui": "@genarrative/shared/components/ui", + "utils": "@genarrative/shared/lib/utils", + "lib": "@genarrative/shared/lib" + } +} diff --git a/docs/README.md b/docs/README.md index 7b24f1cda..f937a964d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -30,6 +30,7 @@ ## 图片画布与媒体 +- [共享基础组件库与展示页](./technical/【前端架构】共享基础组件库与展示页-2026-08-26.md):网站与客户端复用的无业务 UI chrome、样式边界和 `/components` 展示页。 - [客户端素材创作无限画布阶段一合同](./technical/【技术方案】客户端素材创作无限画布阶段一合同-2026-08-05.md) - [图片画布结构化持久化与迁移回滚](./【编辑器】图片画布结构化持久化与迁移回滚方案-2026-07-19.md) - [编辑器生成结果原子提交与幂等重放](./technical/【后端架构】编辑器生成结果原子提交与幂等重放方案-2026-08-06.md) diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 08ddc671c..d2918098b 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -1,4 +1,5 @@ # 决策记录 + > 用途:记录已经确认、会影响后续开发的长期技术/产品/协作决策。短期讨论不要写在这里。 > 当前口径:历史条目的旧路径、旧版本和已退役对象只用于追溯,不构成现行实现依据;如与当前代码或 `docs/README.md` 冲突,以当前代码和最新专题文档为准。 @@ -108,6 +109,7 @@ - 决策:三个工具调用的 arguments 统一限制为 `1 MiB`,先解析通用 JSON 并迭代检查,再进入递归业务类型。结构识别按每棵树独立限制 `512` 个 LLM 节点 / `32` 层,不跨树求和且不计 Rust 页面根;语义建议限制 `4` 节点 / `4` 层;合并计划限制 `512` 节点 / `32` 层。超限整次拒绝,不截断或交付部分结果,日志不记录 arguments 正文。 - 输入边界:`merge_ui` 继续直接接收 `State`,不修改 Tauri/frontend IPC 参数;进入 Rust 后、发起 LLM 前按每棵源树独立限制 `512` 节点 / `32` 层,不跨树求和,并限制 `2 MiB` 序列化投影。UI 设计参考图只设单张 `5 MiB` 上限,不设批次合计或像素数上限;元数据检查、有限读取和 base64 编码进入 blocking worker,不新增命令超时。 - 关联文档:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`。 + ## 2026-08-19 M1 审查后四项可靠性修复 - **审批 stale 收口**:`status` 或 `phase` 为 `needs-reconciliation` 的策划根不再满足审批所需的 active 身份;审批命令返回 `PLAN_STALE_APPROVAL`,并且不得创建 approval receipt。 @@ -152,6 +154,7 @@ - **验证**:`appSurface.test.ts` **381 passed / 0 failed**(378 既有 + 3 新增);`agentTraceSummary` 与 `rememberCommand`(另两个 import `src/App` 的用例文件)13 passed;`agc:typecheck` 通过;6 个改动/新增文件 ESLint `--max-warnings 0` 通过;`check:encoding` 5409 文件通过。不改 Rust——三条全在前端,后端语义已经正确。 - **对既有记录的更正**:M1D-1 与 M1D-2 两条记录分别称「Shell TypeScript typecheck 仍被仓库既有依赖缺失阻断」「appSurface UI suite 受仓库现有缺失 Tauri plugin 依赖阻断,未把该基线失败归因于本包」,在原分支主工作树上都不成立:`agc:typecheck` 干净退出,appSurface 378 条全绿;两道门分别位于 CI 的 `check:native-shells`(且 typecheck 排在 cargo test 之前)与 Frontend tests 内,一直是活的。实际情况与记录相反——`bf2185fba` 改名 `taskGroupLabels.design` 后,appSurface 有 8 个用例文件的断言变红,随后由 `c6a08ef98` 修复;把该套件记为「基线阻断、不归因本包」正是让这条自带回归合入的原因。**隔离工作树的依赖缺失不能作为跳过门禁的依据,须回原工作树复跑后再下结论。** - **未修的审查发现(本次不并入,单列后续)**:① hydrate 在校验 GDD/session 的 projectId 与 manifest 一致之前,已执行 `reconcile_plan_gdd_approval_projections_at`、session previous 提升与 index 重建等落盘修复,违反第 18.3 节固定顺序,其中 `session.previous.json` 的提升+删除不可逆(触发需外部篡改 `.agent/`,App 自身流程造不出该分歧);② 项目写锁竞争时 `acquire_project_write_lock` 的错误原文内嵌项目绝对路径,被原样回传前端,违反第 18.3 节「返回值不包含绝对路径」,常态可达;③ design 组展示名只改了 `taskGroupLabels` 一本字典,`agentPresentation.ts` 的 `groupConfigs` 与 `view/project-development/index.tsx` 的 `summarizeAgent` 仍硬编码「策划 Agent」,与新阶段「立项策划」同屏共存,违反第 18.2 节;④ 阶段进度「轮次 X/3」直接透传 0-indexed 的 `clarificationRound` 未 +1(后端自己用的是 `current_round + 1`),最后一轮显示「轮次 2/3」,字面暗示还剩一轮。 + ## 2026-08-18 M1E 隔离工作树:Fast GDD submit 有界拒绝与覆盖审计 - **范围与结论**:在 `codex/genarrative-isolated` 上按 M1E 只接受具备完整触发链的缺陷。确认 Provider 连续输出不合法 `plan.submit_gdd` 时,Runtime 原有「rejected observation → 同 child run 续跑」链没有次数上限,模型可反复请求 tool-plan 并累积历史 observation;这是可达的 prompt 膨胀与资源消耗链。 @@ -288,7 +291,6 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在 - 不做:改 walker、透明补边、裁切、横纵不同倍率、Lanczos / bilinear、另存逻辑图、前端框缩放、失败路径、新测试。 - 关联文档:`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`、`docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md`、`docs/【编辑器】画板图标素材生成入口设计-2026-06-15.md`、`docs/【编辑器】图片画布结构化持久化与迁移回滚方案-2026-07-19.md`、`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`。 - - 背景:真实 `gpt-5.6-sol / max` 验收中,`art-director` 失败后已形成 `ready + needs-repair` delivery,但认领、合同读取、claim observation 和完成 blocker 均硬编码为 Supervisor-only;实际直属父 Run `code-prototype` 无法消费回执,随后又发起 29 次 Provider 请求。 - 验证方式:覆盖合法认领与合同精确读取、错误 Agent/Run/delegation 拒绝、delivery 身份篡改阻断、唯一安全默认返工、普通失败零后续 Provider lifecycle,以及新的真实 Provider 空项目轮次。顺带收紧 `validate_executable_inline_javascript_syntax`:正文游离 `<` 不再吞掉后续 `