支持App Run并行开发并修复资源画布
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / Frontend tests (pull_request) Successful in 3m28s
Project CI / Native shell tests (pull_request) Failing after 9m27s

新增App Run独立开发profile并隔离端口、数据库、Tauri身份与AppData
常驻资源排列切换并避免布局状态挤压操作入口
显式扩展资源画布横向滚动范围并收敛依赖图可见连线
补充启动器、资源布局、界面回归测试与项目文档
This commit is contained in:
2026-08-07 10:13:25 +08:00
parent dc7c7dc6cc
commit 53e37ea361
21 changed files with 533 additions and 458 deletions
@@ -262,17 +262,17 @@ type UpdateProjectResourceCanvasLayoutResult =
- 阶段五实现状态(2026-08-03):dependency 自动排列同时消费任务 DAG 与精确资源引用。Rust 把可信 producer 的任务深度作为资源深度下限,再对 `asset-reference` 图做迭代式 SCC 压缩与确定性层级传播;被引用资源位于引用资源之前,同一引用环共享稳定深度,环后资源继续递增,没有引用关系的资源保持默认不重叠位置。布局深度通过独立 `dependencyDepths` 返回,不能把 producer assignment 冒充全部资源的布局结果。
- 图层只在 dependency 模式挂载;type 模式不得渲染 SVG、连线或 marker。切换 mode、切换项目或卸载工作台时必须销毁旧图层,并清理尺寸观察和窗口事件监听。
- 输入固定为当前资源投影的全部卡片身份 / 坐标与 Tauri Rust 返回的 `ProjectResourceGraph` 只读 DTO;Rust 负责资源过滤、去重、迭代式环检测、SCC 压缩后的确定性依赖深度、任务流聚合和一跳连接索引,前端只负责 DTO 防御归一化、浏览器几何与原生 SVG path / marker。SVG 叠加在资源卡底层并设置 `pointer-events: none`,不得引入 D3、React Flow 等图表库,也不得阻断卡片点击。
- 输入固定为当前资源投影的全部卡片身份 / 坐标与 Tauri Rust 返回的 `ProjectResourceGraph` 只读 DTO;Rust 负责资源过滤、去重、迭代式环检测、SCC 压缩后的确定性依赖深度、任务流聚合和一跳连接索引,前端只负责 DTO 防御归一化与精确资源引用的浏览器几何。SVG 叠加在资源卡底层并设置 `pointer-events: none`,不得引入 D3、React Flow 等图表库,也不得阻断卡片点击。
- `asset-reference` 表示精确资源引用,使用明亮橙色实线与连续贝塞尔曲线。`GameCreationAppAssetManifestEntry.source.referenceResourceIds` 中的外部资源 ID 必须先唯一匹配另一项资产的 `source.resourceId`,再映射为当前资源卡 ID;缺失、重复或已删除的目标均不得渲染幽灵连线。
- `task-flow` 表示同一资源类型内的任务产物流转,使用灰色圆头虚线;文档、项目版本、美术、音频之间不得绘制跨分区虚线。任务依赖按 `sourceTaskId -> targetTaskId + section` 分区聚合为一条主线,两端只保留同分区资源并绘制平滑曲线分支,不得出现直角折线;禁止对上下游资源生成笛卡尔积连线。任务主线与分支可以使用不同线宽和透明度表达聚合层级,但不能改变端点或方向语义
- `task-flow` 继续作为 Rust 只读拓扑、依赖深度和局部连接索引的数据,不再在资源画布绘制灰色虚线。真实项目的任务产物数量较多,聚合主线与分支仍会形成大面积交叉,不能作为默认用户可读关系;禁止前端重新把 task flow 展开为资源笛卡尔积连线
- 画布资产 producer 只能来自 `agent.runtime.canvas.asset_generate``assetId -> agentId` 审计且 `agentId` 必须存在于当前 manifestExternal Editor `source.taskId` 属于平台生成任务命名空间,禁止当作 manifest task ID。证据缺失、冲突或有界审计读取未覆盖时不生成对应 task flow,不猜测归属。
- 图模型必须对资源引用图和完整任务依赖图做迭代式环检测,不得用无界递归遍历;参与环的可见边保留渲染并标记 cyclic,环本身不能造成重复生成或死循环。
- 资源自引用的起点与终点为同一张卡片时,必须绘制在卡片外侧的可见闭环并保留箭头,不得让路径穿过卡片后被底层 SVG 层级遮挡。
- 搜索只允许为当前可见端点生成几何;任一精确引用端点隐藏时该线隐藏,聚合任务流只保留仍可见的两端分支,任一侧没有可见资源时整条任务流隐藏
- 搜索只允许为当前可见端点生成几何;任一精确引用端点隐藏时该线隐藏。
- 资源点击只进入中央聚焦并保留当前选中卡片,不改变依赖卡片或连线的颜色、线宽与透明度;关系线始终直接展示,不提供点击后的上下游高亮或无关线弱化。
- 资源卡 Pointer Move 不改变基础 positions 或 SVG 几何。连线只随布局读取、资源自动协调、搜索、项目切换或 section origin 变化而更新。
- `ResizeObserver` 在单个图层生命周期只允许构造一次。dependency section 额外提供至少 `64px` 右侧视觉 gutter,确保最右自环和箭头可完整滚动显示,但不得修改卡片坐标或布局 sidecar。
- 阶段五不改变手动位置边界:已有 `manuallyPlaced=true` 坐标原样保留,资源引用新增或变化只允许重新派生 `manuallyPlaced=false` 的自动坐标;任务流继续按任务对与资源分区聚合,禁止为了计算深度或绘线生成资源笛卡尔积
- `ResizeObserver` 在单个图层生命周期只允许构造一次。资源画布内容宽度必须显式覆盖最右卡片外边界、卡片间距和 section 横向内边距,不能依赖绝对定位卡片隐式撑开滚动范围;dependency section 在此基础上额外提供至少 `64px` 右侧视觉 gutter,确保最右卡片、自环和箭头可完整滚动显示,但不得修改卡片坐标或布局 sidecar。
- 阶段五不改变手动位置边界:已有 `manuallyPlaced=true` 坐标原样保留,资源引用新增或变化只允许重新派生 `manuallyPlaced=false` 的自动坐标;任务流继续按任务对聚合供深度计算使用,不进入 SVG 绘制
### 5.3 资源类型与替换兼容性(P1)
@@ -544,12 +544,13 @@ type ProjectAgentMudPointAttribution = {
### 7.3 P1 资源依赖关系图验收
1. dependency 模式显示明亮橙色实线资源引用,并只在同一资源类型分区内显示灰色虚线任务流;跨类型不显示虚线type 模式没有图层或连线。
1. dependency 模式显示明亮橙色实线资源引用,显示灰色任务流虚线type 模式没有图层或连线。资源列表态和资源聚焦态右上角都必须保留“按依赖 / 按类型”切换。
2. 精确引用只接受唯一有效的外部资源 ID 映射,删除或不存在的资源不产生幽灵连线。
3. 多资源任务依赖按资源类型分区后,各分区只形成一条聚合主线与 `O(S+T)` 条端点分支,不产生 `S×T` 连线或跨分区虚线。
3. 多资源任务依赖继续在 Rust read model 中按任务对聚合,不产生 `S×T` 数据或可见虚线。
4. 资源引用环和无资源产物参与的任务环都可被有限遍历识别,界面不死循环。
5. 搜索触发端点过滤;资源点击不改变上下游卡片或任何连线的视觉状态,资源卡指针移动不更新线段,点击与中央聚焦行为不回归。
6. 切换布局模式或项目后旧 SVG、ResizeObserver 与窗口监听全部清理;图层从不写入 layout sidecar、manifest 或其它持久化。
7. 横向滚动终点必须完整露出最右资源卡及右侧安全留白;布局状态文字可以截断或隐藏,但不得压缩、遮挡“按依赖 / 按类型”切换。
7. 4096 资源链式 fixture 继续验证拓扑、聚合复杂度和自动布局性能;拖动局部更新与真实 Chromium 拖动帧预算暂缓,不作为当前验收条件。最右侧自环与箭头仍需完整显示。
8. Rust 图读取延迟时,dependency sidecar 在图进入 `ready / failed` 前没有读取或写入;首次布局直接使用 Rust 返回的最终 producer 与 dependency depth。重新打开旧布局时手动位置逐项不变,自动位置按最终拓扑协调且相同结果不增加 revision。
@@ -1,5 +1,21 @@
# 决策记录
## 2026-08-06 app-run 以独立开发 profile 支持多工作树并行运行
- 背景:多个 Git worktree 能隔离代码和分支,但不会隔离宿主机端口、Tauri identifier、AppData、数据库或本地 data dir。默认 AGC 固定使用 `3080 / 8082 / 8083 / 3101`,另一工作树运行时当前窗口可能被同名实例混淆,默认启动器则会为避免串台直接失败关闭。
- 决策:保留 `npm run agc` 默认行为,新增 `npm run agc:app-run`;两者复用同一 `start-tauri-dev.mjs``start-dev-stack.mjs``app-run` profile 使用 `3081 / 8084 / 8085 / 3103`、专用数据库与 SpacetimeDB data dir,并通过独立 Tauri 配置隔离 identifier、AppData 和窗口标题。profile 随 Tauri 子进程环境传给 `beforeDevCommand`,禁止只切 Vite 而继续连接默认后端。
- 边界:不修改、停止或复用其它工作树进程,不改默认 AGC、game-chat release、生产配置或业务契约;未知 profile 和 profile 自身端口冲突均失败关闭。
- 验证方式:启动器单测锁定 profile 端口、数据库、data dir、3081 预检、Tauri config 与环境传递;配置门禁锁定专用脚本、identifier、标题和 devUrl;并行 smoke 同时核对默认端口仍由另一工作树持有,app-run 端口进程 cwd 指向当前工作树。
## 2026-08-06 资源依赖画布移除任务流虚线并常驻布局切换
- 背景:真实项目会把大量任务产物投影到文档区,灰色 task-flow 聚合主线与分支仍形成大面积交叉,遮挡卡片并增加阅读负担;同时布局状态提示的最小内容宽度可能挤压右侧“按依赖 / 按类型”入口,资源聚焦态还会主动隐藏整组入口。
- 决策:Rust `ProjectResourceGraph` 继续保留 task flow、producer、环和 dependency depth,供可信自动排列与诊断使用;前端 `ResourceDependencyOverlay` 只绘制明确的橙色 `asset-reference`,不再绘制灰色 task-flow 虚线或 marker。资源列表态与中央聚焦态均常驻“按依赖 / 按类型”切换;切换按钮放入不可收缩的独立控件组,工具栏状态文案只能截断或隐藏,不能把操作入口挤出。画布内容宽度显式按最右卡片外边界、section 内边距与 dependency 视觉 gutter 计算,不能依赖绝对定位卡片隐式撑开横向滚动范围。
- 边界:不修改 manifest、资源图 Tauri DTO、依赖深度、layout sidecar、SpacetimeDB 或资源卡拖动边界;type 模式继续不挂载 SVG,dependency 模式仍使用完整 Rust 拓扑排列资源。
- 验证方式:SVG 单测断言含 task flow 的 read model 只产生精确引用 pathAppSurface 覆盖独立布局切换控件组、type 模式卸载图层和聚焦态切换按钮常驻;布局模型以最右 `x` 断言滚动内容宽度包含卡片、列间距、`64px` gutter 与 section 内边距;追加 shell typecheck、编码检查与 `git diff --check`
- 关联文档:`docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md``docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`
## 2026-08-04 工作台 P2/P6 以不可变子版本和编辑态参数文件实现显式写入
- 背景:P1 已建立唯一可运行版本和不可变快照,P3-P5 已建立一次性会话、正式切片和可信悬停信息;飞书后续要求资源替换与数值微调,但禁止原地改版本、运行中热写 iframe、信任展示文案或让自然语言生成任意代码 / 路径。
@@ -59,6 +59,14 @@ AI 游戏创作独立客户端常用短命令:
npm run agc
```
同一台开发机上已有另一工作树运行默认 AGC 时,当前 `app-run` 工作树使用独立 profile
```bash
npm run agc:app-run
```
该 profile 固定使用 Vite `3081`、API `8084`、BgFilter worker `8085`、SpacetimeDB `3103`,并隔离数据库、SpacetimeDB data dir、Tauri identifier、AppData 和窗口标题。它不会探测、复用或停止默认 profile 的 `3080 / 8082 / 8083 / 3101` 进程;`npm run agc` 的默认行为保持不变。
需要构建只能打开“游戏运行 + 聊天”页面的独立 release 包时使用:
```bash
@@ -314,7 +322,7 @@ npm run ai-game-creator-shell:agent-runtime:real-e2e -- --config-dir <AppData> -
定向命令必须实际匹配到 V1.10 用例,`0 tests` 不算通过。真实 Provider fixture 不得把工具顺序、processId、readiness 文本所在 chunk 或 OS PID 写进任务提示;验收器只按持久 action identity、fixture 计数、私有输出和公共泄漏扫描判定。三项门禁实际通过后才能把日期、Provider、数量和 PASS 结果写入技术方案或 decision log;未运行或被外部配置阻断时只记录 `BLOCKED` / 未验收事实。
`npm run agc` 会启动 Tauri 开发客户端;其 `beforeDevCommand` 通过 `npm run agc:serve` 先完成壳 typecheck,再启动或复用配套 SpacetimeDB、`api-server` 和固定 `127.0.0.1:3080` Vite。开发态只打开游戏创作聊天入口使用 `npm run agc:game-chat -- [--project-path <absolute-path>]`。只需要浏览器预览同一客户端时可用 `npm run agc:serve`;只启动配套后端和数据库时可用 `npm run agc:backend -- --database <name>`
`npm run agc` 会启动默认 Tauri 开发客户端;其 `beforeDevCommand` 通过 `npm run agc:serve` 先完成壳 typecheck,再启动或复用配套 SpacetimeDB、`api-server` 和固定 `127.0.0.1:3080` Vite。并行工作树使用 `npm run agc:app-run`,启动器把 `app-run` profile 通过子进程环境传给同一 `beforeDevCommand`,改用独立 `3081 / 8084 / 8085 / 3103` 端口、数据库、data dir 和 Tauri identity;禁止手工只改 Vite 端口而继续连接默认后端或 AppData。开发态只打开游戏创作聊天入口使用 `npm run agc:game-chat -- [--project-path <absolute-path>]`。只需要浏览器预览同一客户端时可用 `npm run agc:serve`;只启动配套后端和数据库时可用 `npm run agc:backend -- --database <name>`
Linux 多用户共享同一台机器开发时,本地 dev 脚本会为当前 Linux 用户分配一个固定端口段并写入系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json`,自动分配从 `10000-10099` 开始,每段 100 个端口,五个 dev 服务依次使用 `start``start + 4`,其中 BgFilter worker 固定为 `start + 4`。可用 `GENARRATIVE_DEV_PORT_RANGE``npm run dev -- --port-range` 手动指定端口段用于特殊场景;注册表会阻止不同用户使用相同或重叠段,并让同一用户后续启动继续复用自己已占用的固定段。该机制只在 Linux 生效,Windows 把第五个服务纳入原有统一端口探测与漂移逻辑。
@@ -14,6 +14,14 @@
- 关联:相关文件、文档、提交或 Issue
```
## 多工作树只隔离代码,不会自动隔离 AGC 运行资源
- 现象:两个工作树同时运行 `npm run agc` 时,后启动者因 `3080` 已占用而失败,或用户在两个同名窗口间误把另一工作树的页面当作当前修改结果。
- 原因:worktree 只隔离 Git 工作目录;端口、Tauri identifier、AppData、SpacetimeDB 数据库和 data dir 都属于宿主机共享资源。只修改 Vite 端口仍会让代理、Runner 或数据库串到默认实例。
- 处理:默认工作树继续使用 `npm run agc`;当前 app-run 使用 `npm run agc:app-run`,由统一 profile 同时隔离 `3081 / 8084 / 8085 / 3103`、数据库、data dir、Tauri identifier、AppData 和窗口标题。不要手工终止无法证明归属的进程,也不要只覆盖单个端口。
- 验证:分别用 `lsof -a -p <pid> -d cwd -Fn` 核对两组监听进程 cwd;app-run 窗口标题必须为“AI 游戏创作 · App Run”,Vite marker API target 必须指向 app-run 的实际 API。
- 关联:`apps/ai-game-creator-shell/scripts/start-tauri-dev.mjs``apps/ai-game-creator-shell/scripts/start-dev-stack.mjs``apps/ai-game-creator-shell/src-tauri/tauri.app-run-dev.conf.json``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`
## Linux 生产脚本门禁不能假设本地也是 GNU userland
- 现象:macOS 本地运行维护页、生产 API 部署和 Rust 产物门禁时,依次出现 `mv: illegal option -- T``mapfile: command not found``/usr/bin/cp` / `/usr/bin/chmod` 不存在,以及 `.rlib` 明明含有 `.o` 却报告“没有可扫描成员”;安全修复计划还会把 `/var/folders``/private/var/folders` 的系统别名误判为用户符号链接。
@@ -362,7 +362,7 @@ game-project/
- 页面骨架固定为左侧现有全局导航、中间主视窗、右侧陶泥儿对话和底部子 Agent 状态栏;不新建第二套客户端或平行项目页。
- 中间主视窗提供 `资源管理 / 运行` 切换。2026-08-04 起运行入口不再读取 `code-prototype` 任务状态,只读取 manifest 的正式 `runnableVersions + currentRunnableVersionId`;无版本时保持视觉不可用但仍可点击查看“当前无可运行版本”,不能使用会阻断说明交互的原生 `disabled``aria-disabled`。切回资源管理只修改前端展示态,不伪造后端预览暂停结果。
- 资源管理从当前 `GameCreationAppManifest`(包含可选 `versions`)、合法 Agent 文本回执和已导入附件派生资源,固定按文档、项目版本、美术资源、音乐音效资源分区;未知任务产物不再兜底为版本,任务声明中的未登记音频也不冒充正式音频。`按依赖 / 按类型` 使用各自前端排列dependency 模式额外绘制当前 manifest 与资源投影可证明的依赖关系。排列与图层都不写回 manifest,不能推断或伪造缺失依赖。
- 资源管理从当前 `GameCreationAppManifest`(包含可选 `versions`)、合法 Agent 文本回执和已导入附件派生资源,固定按文档、项目版本、美术资源、音乐音效资源分区;未知任务产物不再兜底为版本,任务声明中的未登记音频也不冒充正式音频。`按依赖 / 按类型` 使用各自前端排列并在资源列表态、聚焦态常驻右上角;dependency 模式额外绘制当前 manifest 与资源投影可证明的精确资源引用。排列与图层都不写回 manifest,不能推断或伪造缺失依赖。
- 资源卡支持点击聚焦、搜索和类型筛选。2026-07-28 起完成两套二维坐标与本地 CAS sidecar2026-07-31 起 dependency 模式增加不持久化的原生 SVG 关系图层。2026-08-03 mentor 决定暂缓资源卡拖动,当前卡片不挂载 Pointer Down / Move / Up / Cancel 拖动入口,只允许自动布局和点击聚焦。聚焦态替换中央主视窗内容,保留左侧导航、右侧对话和底部 Agent 状态栏,退出后恢复搜索、布局模式、滚动位置与选中资源;不提供工具栏、工具侧边栏或可拖动标题栏。阶段四已补齐安全本地文档、扩展美术媒体与音频聚焦,正文独立滚动,视频 / 音频使用内置媒体控件,失败显示空态;美术编辑、音频编辑 / 替换、版本替换或运行模块仍不在本阶段。
- 运行表现层嵌入当前项目的 loopback 游戏画面。P1 由专用可运行版本命令停止旧 preview、卸载 iframe、复核版本快照并启动目标版本;普通 `preview.start` 继续服务 Agent 当前工作树验证,不能作为工作台运行授权或旧版本切换入口。2026-08-04 起 P3 在该生命周期上接入运行会话与 Host/Game Bridge;P3 阶段自身未接入资源替换、下一版本、测试切片编排或参数调整,P2 / P6 的当前实现以本节后续对应专节为准。
- 右侧继续复用现有 Project Supervisor 会话、Runtime 澄清和确认链路;输入区展示 `严格审批 / 风险审批 / 无需审批` 独立面板。P0 只有严格审批可选;风险审批和无需审批保持视觉不可用但允许点击查看原因,不替代 Runtime 的逐动作权限、确认、sandbox 或 reconciliation 门禁。风险 Rank 算法记录在 `docs/project-memory/todos/【待解决】AI游戏创作高风险审批Rank-2026-07-20.md`,前端不得自行计算。
@@ -402,10 +402,10 @@ game-project/
- `read_local_project_resource_graph` 读取当前 manifest、前端资源卡身份列表和最多 `32 MiB` 的安全 Agent DB 尾部,通过 Rust 构建稳定 read model;读取使用既有 Agent DB 普通文件 / 链接 / 追加锁边界,不新增数据库或 sidecar。返回资源 ID、引用边、聚合任务流、producer assignment、独立 `dependencyDepths`、循环集合、unresolved 外部 ID、局部连接索引和 `producerMappingTruncated`
- 精确引用把 manifest 资产 `source.referenceResourceIds` 唯一匹配到另一资产的 `source.resourceId`,再转换为本次资源卡 ID;无匹配、多匹配、重复卡片或已删除资源只记录为 unresolved / 忽略,不生成边。引用边按 `sourceResourceId + targetResourceId` 稳定去重;前端 `resourceDependencyGraphModel.ts` 再做一次 DTO 端点防御过滤,避免异步切项目时出现幽灵线。
- task flow 只读取存在于当前 manifest 的任务依赖。画布资产 producer 仅接受 `agent.runtime.canvas.asset_generate` 中经 manifest 校验的 `assetId -> agentId`External Editor 返回并保存在 `source.taskId``task-1` 等身份属于平台生成任务,禁止复用为 manifest task。多个有效 Agent 对同一资产形成冲突或证据缺失时,不生成该资产对应 task flow。任务产物 / Agent 回执继续使用资源投影中已有的 manifest task 身份。
- 资源按可信 producer 分组,每个 `sourceTaskId -> targetTaskId` 只生成一个聚合 flowSVG 绘制 source 分支、唯一主线和 target 分支,路径数量为 `O(S+T)`,禁止资源笛卡尔积。局部连接索引保存 resource 关联的 reference edge ID / task flow ID,不预先展开 `S×T` 邻接矩阵。
- 资源按可信 producer 分组,每个 `sourceTaskId -> targetTaskId` 只生成一个聚合 flow,供依赖深度、环检测和局部连接索引使用;前端 SVG 不再绘制 task flow。局部连接索引保存 resource 关联的 reference edge ID / task flow ID,不预先展开 `S×T` 邻接矩阵。
- 资源引用图和完整任务依赖图在 Rust 分别使用迭代式强连通分量分析。任务环检测不能依赖可视 task flow 是否有两端资源,否则无产物任务参与的环会漏报;循环边只带 cyclic 标记,不触发递归展开。
- `ResourceDependencyOverlay.tsx` 使用原生 SVG path/marker,绝对定位在 `.game-resource-canvas-content` 底层并统一 `pointer-events: none`。橙色实线表示 `asset-reference`灰色圆头虚线表示 `task-flow`;两类连线统一使用连续贝塞尔曲线,任务主线略强于两端分支,箭头使用不随高亮线宽缩放的稳定用户空间尺寸,避免直角折线、突兀拐弯和箭头跳变。不引入 D3、React Flow 或其它图表依赖。
- `asset-reference` 的 source / target 是同一资源时使用卡片右侧外绕贝塞尔闭环,两个锚点分开且 marker 保留在返回锚点;路径不穿过卡片。dependency section 在现有 extent 外额外增`64px` 右侧视觉 gutter,确保最右卡片闭环和箭头可滚动显示;不改卡片坐标、`resourceCanvasLayoutModel.ts` sidecar。
- `ResourceDependencyOverlay.tsx` 使用原生 SVG path/marker,绝对定位在 `.game-resource-canvas-content` 底层并统一 `pointer-events: none`图层只绘制橙色实线 `asset-reference`不绘制灰色 task flow 虚线;资源引用使用连续贝塞尔曲线和不随线宽缩放的稳定用户空间箭头。不引入 D3、React Flow 或其它图表依赖。
- `asset-reference` 的 source / target 是同一资源时使用卡片右侧外绕贝塞尔闭环,两个锚点分开且 marker 保留在返回锚点;路径不穿过卡片。`.game-resource-canvas-content` 使用 `resourceCanvasContentWidth(...)` 显式覆盖最右坐标、卡片宽度、列间距与 section 横向内边距,避免绝对定位卡片溢出却没有进入 `scrollWidth`dependency 模式再追`64px` 右侧视觉 gutter,确保最右卡片闭环和箭头可滚动显示。该宽度只影响显示层,不改卡片坐标或 layout sidecar。
- 图层用 SVG 自身节点定位所属画布容器,测量各 section plane 相对原点;`ResizeObserver` 在图层挂载时只创建一次,与 window resize 一起负责重新测量并在卸载时清理。type 模式不挂载图层且释放 graph state;项目身份作为 key,切换 mode、项目或工作台卸载都会销毁旧 SVG。
- 基础 positions 保持稳定;卡片 Pointer Move 不进入 SVG preview,只有搜索、选择、项目切换、真实 positions 或 section origin 变化才重新协调图层。SVG 几何从不持久化。
- Rust、前端 DTO/SVG 和工作台 AppSurface 回归覆盖生产 `task-1` 数据形状、真实 producer、证据缺失、精确引用、去重、无效 ID、完整任务环、4096 链式拓扑、聚合复杂度、搜索过滤、选择高亮、稳定 Observer、type 模式卸载与项目切换销毁。局部拖动更新与真实 Chromium 拖动性能目标暂缓。
@@ -58,7 +58,9 @@ Linux 本机多用户并发开发时,`npm run dev` 和 `npm run dev:*` 单模
后端日志默认写入 `logs/api-server/`,独立 BgFilter worker 日志默认写入 `logs/bgfilter-worker/`。后端 API smoke 使用 `npm run dev:api-server`,先检查 BgFilter worker `/readyz`,再检查 API `/healthz`;需要确认 API 实例可接生产流量时检查 API `/readyz`。不要使用旧 `api-server:maincloud` 或任何 `GENARRATIVE_SPACETIME_MAINCLOUD_*` 口径。
AI 游戏创作客户端使用 `npm run agc`,开发态 game-chat 使用 `npm run agc:game-chat`。两个入口都先由 `apps/ai-game-creator-shell/scripts/start-tauri-dev.mjs` 在 Tauri CLI 启动前检查固定地址 `http://127.0.0.1:3080/`:只有端口空闲时才继续启动。现有 marker 只包含 API target,不能证明监听器属于当前 worktree;即使页面和 target 看似匹配,也不得复用已经存在的 3080。旧 worktree Vite、无响应监听器或非 AGC 服务一律在创建原生窗口前失败关闭,并提示先停止旧服务;启动器不擅自终止无法证明归属的进程。
AI 游戏创作客户端默认使用 `npm run agc`,开发态 game-chat 使用 `npm run agc:game-chat`。两个入口都先由 `apps/ai-game-creator-shell/scripts/start-tauri-dev.mjs` 在 Tauri CLI 启动前检查固定地址 `http://127.0.0.1:3080/`:只有端口空闲时才继续启动。现有 marker 只包含 API target,不能证明监听器属于当前 worktree;即使页面和 target 看似匹配,也不得复用已经存在的 3080。旧 worktree Vite、无响应监听器或非 AGC 服务一律在创建原生窗口前失败关闭,并提示先停止旧服务;启动器不擅自终止无法证明归属的进程。
同一台机器需要并行运行另一工作树时,`app-run` 工作树使用 `npm run agc:app-run`。该命令仍复用同一 Tauri / dev-stack 启动器,但使用独立 profileVite `3081`、API `8084`、BgFilter worker `8085`、SpacetimeDB `3103`、数据库 `genarrative-game-creator-app-run-dev`、独立 SpacetimeDB data dir,以及独立的 Tauri identifier、AppData 和“AI 游戏创作 · App Run”窗口标题。profile 只检查和清理自己创建的进程树,不复用、不终止默认 profile 或其它工作树进程。若 profile 自己的端口被占用则失败关闭,不能漂回默认端口。
Tauri `beforeDevCommand` 默认与客户端构建并行,不能把上述检查只放在 `beforeDevCommand` 内:旧 3080 已就绪时,Tauri 可能先创建加载旧前端的窗口,随后配套后端才因代理不匹配退出。外层启动器会把 Tauri CLI 放入受控进程树;CLI 正常退出、启动失败或收到终止信号后,POSIX 先向保留的 PGID 发送 `SIGTERM`、有界等待后升级 `SIGKILL`Windows 使用 `taskkill /PID <pid> /T /F`。Linux 容器中的孤儿后代退出后可能暂时保留为 zombie,`kill(-PGID, 0)` 仍会返回成功;启动器必须结合 `/proc/<pid>/stat` 判断同组是否还存在非 zombie 成员,不能把等待 PID 1 回收误报为清理失败。配套后端和 Vite 仍由 `start-dev-stack.mjs` 各自持有,退出时同样有界收束,避免只剩客户端、Runner、Cargo 或旧订阅进程。排障时同时核对 3080 marker、`.app/dev-stack.json` 的实际 API URL 和进程 cwd;不要把“终端已返回”当成客户端及其 Runner 已退出的证据。