纳入 AGC Cargo workspace 的统一 rustfmt 检查与格式化入口 完成项目 TypeScript/Prettier 与 Rust 全量格式化 修复 Pingora expected executable 门禁的空白敏感误报 同步开发运维文档与 AGC skill pack 格式化忽略规则
11 KiB
name, description, license, metadata
| name | description | license | metadata | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| genarrative-dev-stack-port-routing | 在 Genarrative 中修改 npm run dev / dev:spacetime / dev:api-server / dev:bgfilter-worker / dev:web / dev:admin-web 的本地启动端口、端口可用性探测、端口漂移、SpacetimeDB publish server、Rust 进程环境变量、Vite 代理目标和后台 admin-web 启动串联时使用。 | MIT |
|
Genarrative 本地 dev 启动端口与代理目标串联流程
用于维护 Genarrative 本地开发栈启动脚本,重点覆盖 npm run dev 与五个 dev:* 单模块命令的端口检查、端口漂移和后续流程目标传递。
适用场景
- 修改
scripts/dev.mjs、scripts/dev-utils.mjs、scripts/dev-stack-port-utils.mjs或 AI 游戏创作客户端 dev 启动器。 - 处理
3000、3101、3102、8082等端口被占用导致本地开发栈启动失败。 - 排查 Vite 代理仍指向旧 api-server 端口、前端打开了旧 dev server、后台代理错配。
- 调整 SpacetimeDB standalone、publish、Rust
api-server、主站 Vite、后台 Vite 的启动顺序。 - 修改本地联调文档或
docs/project-memory/shared-memory/pitfalls.md中的 dev 启动口径。
当前端口职责
默认优先端口:
- 主站 Vite:
3000,对浏览器通常展示为http://127.0.0.1:<web-port>/。 - Rust
api-server:8082,健康检查为http://127.0.0.1:<api-port>/healthz。 - SpacetimeDB standalone:
3101,健康检查为http://127.0.0.1:<spacetime-port>/v1/ping。 - 后台 Vite:
3102,后台地址为http://127.0.0.1:<admin-web-port>/admin/。 - 独立 BgFilter worker:
8083,就绪检查为http://127.0.0.1:<bgfilter-worker-port>/readyz。 - AI 游戏创作 Vite:非 Linux 兼容首选
3080;Linux 使用当前用户端口段的start + 5。
端口不可用时,脚本会从优先端口开始向后寻找可用端口。后续流程必须以解析后的实际端口为准,不能继续使用默认端口。
Linux 多用户并发开发时,GENARRATIVE_DEV_PORT_RANGE 或 --port-range 会先向系统级注册表 /var/tmp/genarrative-dev-port-ranges/registry.json 申请一个端口段,再把该段映射为 web = start、api = start + 1、spacetime = start + 2、adminWeb = start + 3、bgfilterWorker = start + 4、agcVite = start + 5。注册表锁文件是 /var/tmp/genarrative-dev-port-ranges/registry.lock,可通过 GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR 覆盖目录。自动分配从 10000-10099 起,每次占用 100 个端口块,后续块按 10100-10199、10200-10299 递增;当前口径是“一个用户固定占用一个段,后续启动继续复用这段并在段内漂移”;该注册表只在 Linux 上生效;Windows 继续沿用原有统一端口探测和漂移逻辑,不读系统级注册表。
实现入口
package.jsondev:执行node scripts/dev.mjs,启动完整五服务。dev:spacetime/dev:api-server/dev:bgfilter-worker/dev:web/dev:admin-web:执行node scripts/dev.mjs <module>;dev:api-server会安全带起其依赖的 BgFilter worker。
scripts/dev-stack-port-utils.mjsisPortAvailable(...):探测端口是否可监听。findAvailablePort(...):从优先端口向后寻找可用端口,0表示申请临时端口。resolveDevStackPorts(...):一次性解析 SpacetimeDB、api-server、主站 Vite、后台 Vite、BgFilter worker 端口,并避免本次解析结果互相冲突。- Linux 注册表分配:
reserveLinuxDevPortRange(...)/releaseLinuxDevPortRange(...),仅在 Linux 上启用系统级端口段登记与用户段复用,自动分配从10000-10099起。 - CLI 模式:
node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:3101 api:127.0.0.1:8082 web:0.0.0.0:3000 adminWeb:127.0.0.1:3102 bgfilterWorker:127.0.0.1:8083。
scripts/dev.mjs- 解析 CLI 参数后统一计算 client host、端口、
SPACETIME_SERVER、RUST_SERVER_TARGET。 - 完整栈按 SpacetimeDB、publish、BgFilter worker readiness、api-server readiness、主站 Vite、后台 Vite 顺序启动。
- Linux 下会先申请系统级端口段并映射成六个预留槽位;主 dev 栈使用前五个,AGC Vite 使用
start + 5,自动分配从10000-10099起。Windows 的主 dev 栈和 AGC 则各自沿用统一端口探测与漂移逻辑。 - 完整栈和
dev:api-server把两个 Rust 进程作为同一重启单元,先全部停止,再先启动 BgFilter worker、后启动 api-server;不要为同一份 Rust 源码创建两个并发cargowatcher。 - 单模块命令复用同一套参数和 env 解析。
- 解析 CLI 参数后统一计算 client host、端口、
apps/ai-game-creator-shell/scripts/dev-port.mjs- 复用系统级用户端口段,解析 AGC Vite 的
start + 5首选槽位。 - 把最终端口通过
GENARRATIVE_AGC_VITE_PORT同步给beforeDevCommand和配套后端端口解析器,通过 Tauri CLI--config同步build.devUrl,并通过 Vite CLI--port同步strictPort监听。
- 复用系统级用户端口段,解析 AGC Vite 的
必须保持的传递链路
npm run dev 和五个 dev:* 单模块命令中端口解析后,必须同步到以下位置:
- SpacetimeDB 启动:
spacetime start --listen-addr "${SPACETIME_HOST}:${SPACETIME_PORT}"。 - SpacetimeDB 发布:
spacetime publish ... --server "${SPACETIME_SERVER}"。 - Rust api-server:
GENARRATIVE_API_HOST、GENARRATIVE_API_PORT、GENARRATIVE_SPACETIME_SERVER_URL、GENARRATIVE_SPACETIME_DATABASE。 - api-server 健康检查:
wait_for_api_server "${RUST_SERVER_TARGET}/healthz" ...。 - BgFilter worker:
GENARRATIVE_PROCESS_ROLE=bgfilter-worker、解析后的HOST / PORT、与父 API 相同的GENARRATIVE_BGFILTER_WORKER_BASE_URL/GENARRATIVE_BGFILTER_INTERNAL_TOKEN,以及显式有效的N / Q。 - BgFilter worker readiness:父 API 启动前检查解析后地址的
/readyz。 - 主站 Vite:
RUST_SERVER_TARGET、GENARRATIVE_RUNTIME_SERVER_TARGET、ADMIN_WEB_TARGET、ADMIN_WEB_PORT、--port=${WEB_PORT}、--host=${WEB_HOST}。 - 后台 Vite:
ADMIN_API_TARGET、GENARRATIVE_API_TARGET、GENARRATIVE_API_PORT、--port=${ADMIN_WEB_PORT}。 - 控制台日志:
[dev:ports]和[dev] web/admin web/api-server/bgfilter-worker/spacetime必须显示最终实际地址。 - Linux 端口段注册:
[dev] port-range:与[dev] port-range-registry:只在 Linux 输出,Windows 不应依赖系统级注册表。 - AI 游戏创作客户端:外层启动器解析最终 AGC Vite 端口后,通过 Tauri CLI
--config覆盖build.devUrl,把同一GENARRATIVE_AGC_VITE_PORT传给beforeDevCommand与配套后端端口解析器,并用 Vite CLI--port启动严格监听;后端端口漂移必须跳过该预留端口。
如果只改了其中一段,通常会出现:浏览器打开的前端可用,但 /api/* 代理到旧端口;后台页面可用但后台 API 失败;SpacetimeDB 启动在新端口但 publish 仍发往旧端口。
修改流程
- 先读当前脚本和文档:
scripts/dev-stack-port-utils.mjsscripts/dev.mjsscripts/dev-utils.mjsdocs/【开发运维】本地开发验证与生产运维-2026-05-15.mddocs/project-memory/shared-memory/pitfalls.md
- 优先改公共端口工具,不要把端口探测逻辑复制到多个脚本。
- 修改
scripts/dev.mjs时确认变量顺序:先解析参数和端口,再构造SPACETIME_SERVER/RUST_SERVER_TARGET,最后启动对应 service。 - 修改 watch 时保持模块边界:SpacetimeDB 只监听
spacetime-module且改动后重新 publish,不重启 standalone 宿主;api-server 排除spacetime-module;web/admin-web 源码变化交给 Vite 自身 HMR,外层调度器不要再监听前端目录重启 Vite。 - 修改
dev:web时不要自动改后端目标策略;dev:web只负责主站 Vite 端口可用性与已有后端目标选择。 - 同步更新技术文档和团队共享记忆。
- 如果修改 Linux 端口段注册口径,确认 Windows 分支仍保持旧行为,不要把系统级注册表逻辑扩散到 Windows。
测试与验证
最小验证:
node --check scripts/dev.mjs
npm run test -- scripts/dev-stack-port-utils.test.ts
npm run check:encoding
node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:0 api:127.0.0.1:0 web:0.0.0.0:0 adminWeb:127.0.0.1:0 bgfilterWorker:127.0.0.1:0
端口冲突回归测试建议:
- 用测试或临时 Node server 占用某个优先端口。
- 调用
findAvailablePort,断言结果大于被占用端口。 - 调用
resolveDevStackPorts,断言五个结果互不相同。 - 如果实际启动完整栈,观察控制台:
[dev:ports] ... 不可用,改用 ...[dev] api-server: http://...:<actual-api-port>[dev] spacetime: http://...:<actual-spacetime-port>- 主站和后台 Vite 启动端口与日志一致。
完整启动属于长驻进程。需要 smoke 时用 background 方式启动,并另开命令检查 api-server /healthz、BgFilter worker /readyz、SpacetimeDB /v1/ping 和两个页面端口;不要等待 npm run dev 自然退出。检查地址必须取 .app/dev-stack.json 或启动日志中的实际端口,不能假定 worker 一定停在 8083。
常见坑
- 只让 Vite 自己漂移端口。 这样终端可能出现可访问前端,但脚本和文档仍认为是
3000,后台目标或日志会错。 - 只改 SpacetimeDB start,不改 publish。 standalone 可能监听新端口,但 publish 仍连旧
3101。 - 只改
GENARRATIVE_API_PORT,不改RUST_SERVER_TARGET。 api-server 已在新端口监听,但 Vite 代理仍打旧端口。 - 使用
0.0.0.0作为浏览器访问地址。 监听可以是0.0.0.0,展示给用户和健康检查通常用127.0.0.1。 - 端口探测和实际启动之间存在竞态。 已经探测可用的端口仍可能被外部进程抢占;SpacetimeDB 启动后仍要解析实际监听地址,api-server 和 Vite 失败时要打印清晰日志。
- 运行全仓库 lint 误判。 当前仓库可能有既有 lint 问题。验证本功能时优先运行定向测试、Bash 语法检查、编码检查,并在最终说明中区分既有 lint 失败与本次改动。
验收清单
- 端口工具有测试覆盖端口被占用和多端口互斥解析。
- Linux 注册表分配、同用户复用固定段并继续漂移、自动分配从
10000-10099起、Windows bypass 都有测试覆盖。 scripts/dev.mjs通过node --check。npm run dev的 SpacetimeDB、publish、api-server、主站 Vite、后台 Vite 都使用实际端口。- BgFilter worker 在 api-server 前 ready,父子共享实际 base URL / Token,Rust watch 只触发一次组合重启。
npm run dev:web在主站端口不可用时能切换到可用端口。npm run agc在 Linux 使用用户段start + 5,Tauri、Vite、marker 和预检使用同一最终端口。- 文档同步更新
docs/【开发运维】本地开发验证与生产运维-2026-05-15.md。 - 长期踩坑同步更新
docs/project-memory/shared-memory/pitfalls.md。 - 修改中文文件后运行
npm run check:encoding。