Merge branch 'master' of http://82.157.175.59:3000/GenarrativeAI/Genarrative
This commit is contained in:
@@ -16,6 +16,22 @@
|
||||
|
||||
---
|
||||
|
||||
## 2026-05-10 运行态输入设备抽象层全项目通用化
|
||||
|
||||
- 背景:拼图运行态接入 mocap 后,鼠标/触控和 mocap 各自维护输入逻辑会导致合并大块、拖拽语义和取消会话行为不一致;后续其他玩法也需要复用体感、摇杆、键盘等设备输入。
|
||||
- 决策:前端运行态输入统一通过 `src/services/input-devices/` 承接,设备适配层只输出 `press / move / release / tap / drop` 等通用语义和通用坐标;玩法组件自己解释目标对象、落点和业务动作,输入层不得写拼图等玩法专用规则。
|
||||
- 影响范围:拼图运行态鼠标/触控/mocap 输入、后续运行态设备接入、运行态输入技术文档与相关前端回归测试。
|
||||
- 验证方式:执行 `npm run test -- src\services\input-devices\runtimeDragInputController.test.ts`、`npm run test -- src\components\puzzle-runtime\PuzzleRuntimeShell.test.tsx`、`npm run typecheck` 和编码检查。
|
||||
- 关联文档:`docs/technical/RUNTIME_INPUT_DEVICE_ABSTRACTION_2026-05-10.md`、`docs/technical/PUZZLE_RUNTIME_FRONTEND_LOGIC_REHOME_2026-05-02.md`。
|
||||
|
||||
## 2026-05-10 儿童动作热身关直接消费 mocap 手势流
|
||||
|
||||
- 背景:儿童动作 Demo 的挥手、左右手挥动和跳跃阶段不能只依赖键鼠调试输入,否则真实硬件接入后会出现“能看到画面但动作不推进”的卡点。
|
||||
- 决策:热身关在 gesture 阶段直接接入 `useMocapInput`,通过本地 mocap WebSocket `/stream` 消费 `actions/action/gesture/gestures/event/name/type` 动作名,以及 `hands[]`、`leftHand/rightHand`、`left_hand/right_hand` 手部坐标;`wave_greeting`、`wave_left_hand`、`wave_right_hand` 和 `jump_once` 都可以由 mocap 包推进,同时保留键鼠作为本地调试兜底。
|
||||
- 影响范围:`src/services/useMocapInput.ts`、`src/components/child-motion-demo/ChildMotionWarmupDemo.tsx`、对应单测与热身关技术文档。
|
||||
- 验证方式:执行 `npx vitest run src/components/child-motion-demo/ChildMotionWarmupDemo.test.tsx src/components/child-motion-demo/childMotionWarmupModel.test.ts src/services/child-motion-demo/childMotionDebugInput.test.ts src/routing/appRoutes.test.ts`、`npx eslint ...`、`npm run typecheck`、`npm run check:encoding`,并确认 `http://127.0.0.1:3000/child-motion-demo` 与 `http://127.0.0.1:3100/healthz` 可访问。
|
||||
- 关联文档:`docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md`。
|
||||
|
||||
## 2026-05-09 GPT-image-2 图片生成统一迁移到 VectorEngine
|
||||
|
||||
- 背景:仓库内 RPG、拼图、方洞和本地模板脚本的 GPT-image-2 生图此前依赖 APIMart 图片网关;团队要求参考 VectorEngine Apifox `api-448710071`,后续不再使用 APIMart 执行 GPT-image-2 图片生成。
|
||||
|
||||
@@ -43,6 +43,14 @@
|
||||
- 验证:提交前检查 `git diff -- .hermes`,确认没有密钥、会话记录或个人路径敏感信息。
|
||||
- 关联:`.hermes/README.md`。
|
||||
|
||||
## 儿童动作 Demo 挥手阶段不推进先查 mocap 消费链路
|
||||
|
||||
- 现象:`/child-motion-demo` 能打开摄像头画面,但到“打个招呼”或左右手挥动阶段时,真实硬件动作无法检测通过,只能用鼠标拖拽或键盘调试继续。
|
||||
- 原因:摄像头视频流只是舞台背景;如果热身关没有消费 `useMocapInput` 的动作名和手部坐标,就不会把硬件动作转换成热身状态机完成事件。
|
||||
- 处理:确认 `src/components/child-motion-demo/ChildMotionWarmupDemo.tsx` 在 `step.kind === 'gesture'` 时启用 `useMocapInput`;确认 `src/services/useMocapInput.ts` 能解析 `/stream` 包里的 `actions/action/gesture/gestures/event/name/type`、`hands[]`、`leftHand/rightHand`、`left_hand/right_hand`、左右手标记和 `open_palm/grab` 状态。热身关应由 mocap 推进,键鼠只作为本地调试兜底。
|
||||
- 验证:运行 `npx vitest run src\components\child-motion-demo\ChildMotionWarmupDemo.test.tsx`,并在本地硬件服务启动后进入 `/child-motion-demo` 实测招手、左右手挥动和跳跃阶段。
|
||||
- 关联:`src/services/useMocapInput.ts`、`src/components/child-motion-demo/ChildMotionWarmupDemo.tsx`、`docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md`。
|
||||
|
||||
## GPT-image-2 不再读 APIMart 图片配置
|
||||
|
||||
- 现象:配置了 `APIMART_BASE_URL` / `APIMART_API_KEY` 后,RPG、拼图或方洞的 GPT-image-2 生图仍返回缺配置,或请求体里还出现 `official_fallback` / `image_urls`。
|
||||
@@ -119,8 +127,8 @@
|
||||
|
||||
- 现象:本地 `npm run dev` 因 `3101` 已占用、重复发布 SpacetimeDB wasm 编译太慢,或只想检查 `spacetime-module` 语法而被完整联调链路拖慢。
|
||||
- 原因:`npm run dev` 默认同时启动 SpacetimeDB standalone、发布 `server-rs/crates/spacetime-module`、启动 Rust `api-server`、主站 Vite 与后台 Vite;并非每个阶段都需要完整重启和重新发布。
|
||||
- 处理:`npm run dev` 启动后会把实际 SpacetimeDB URL 记录到 `server-rs/.spacetimedb/local/data/dev-rust-spacetime-url`。下次启动即使没有传 `--skip-spacetime`,脚本也会先检查 `spacetime.pid` 对应进程和该 URL 是否在线;在线则直接复用现有宿主。确认需要新启动 SpacetimeDB 时,脚本先检测 `3101`,被占用则输出占用进程并选择最近可用端口,保证 publish 与 `api-server` 都连接同一个实际 SpacetimeDB URL。`api-server` 启动前也会检测 `8082` 并选择最近可用端口。Windows / Git Bash 下不要用 `tr/head/xargs` 管道读取 `spacetime.pid` 或 URL 记录,脚本应使用 Node 读取并短重试,避免 `tr: read error: Device or resource busy`;未修改 `spacetime-module` 时使用 `npm run dev -- --skip-publish`;只查模块语法时执行 `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`。
|
||||
- 验证:`--skip-spacetime` 后脚本复用现有 `http://127.0.0.1:3101`;`3101` 或 `8082` 被其他进程占用时,脚本输出占用进程并使用最近可用端口;`--skip-publish` 后不再进入 publish 阶段;`cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml` 能完成 Rust 语法和类型检查。
|
||||
- 处理:`npm run dev` 启动后会把实际 SpacetimeDB URL 记录到 `server-rs/.spacetimedb/local/data/dev-rust-spacetime-url`。下次启动即使没有传 `--skip-spacetime`,脚本也会先检查 `spacetime.pid` 对应进程和该 URL 是否在线;在线则直接复用现有宿主。确认需要新启动 SpacetimeDB 时,脚本先检测 `3101`,被占用则输出占用进程并选择最近可用端口,保证 publish 与 `api-server` 都连接同一个实际 SpacetimeDB URL。`api-server` 启动前也会检测 `8082` 并选择最近可用端口。Windows / Git Bash 下不要用 `tr/head/xargs` 管道读取 `spacetime.pid` 或 URL 记录,脚本应使用 Node 读取并短重试,避免 `tr: read error: Device or resource busy`;未修改 `spacetime-module` 时使用 `npm run dev -- --skip-publish`;只查模块语法时执行 `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`。`npm run dev` 会在启动前检查 SpacetimeDB、api-server、主站 Vite、后台 Vite 端口,不可用时自动寻找后续可用端口,并把实际端口传给 publish、后端环境变量和前端代理目标。
|
||||
- 验证:`--skip-spacetime` 后脚本复用现有 `http://127.0.0.1:3101`;`3101` 或 `8082` 被其他进程占用时,脚本输出占用进程并使用最近可用端口;`--skip-publish` 后不再进入 publish 阶段;`cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml` 能完成 Rust 语法和类型检查。端口漂移时控制台会打印 `[dev:ports] ... 不可用,改用 ...`,后续 `[dev:rust] web/admin web/rust api/spacetime` 地址应与实际端口一致。
|
||||
- 关联:`docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md`、`scripts/dev-rust-stack.sh`。
|
||||
|
||||
## 本地 SpacetimeDB publish 401 可清本地库重发
|
||||
@@ -191,6 +199,14 @@
|
||||
- 验证:`http://127.0.0.1:3000/api/auth/login-options` 返回至少 `{"availableLoginMethods":["phone","password"]}` 后,登录弹窗会恢复短信登录页签和“获取验证码”按钮。
|
||||
- 关联:`scripts/api-server-dev.mjs`、`scripts/api-server-maincloud.mjs`、`scripts/dev-rust-stack.sh`、`scripts/dev-web-rust.mjs`、`docs/technical/AUTH_LOGIN_OPTIONS_DESIGN_2026-04-21.md`。
|
||||
|
||||
## 本地短信收不到验证码先查 provider
|
||||
|
||||
- 现象:登录弹窗可以进入短信页签,但点击“获取验证码”后,手机没有收到短信。
|
||||
- 原因:本地 `.env.local` 里如果是 `SMS_AUTH_PROVIDER="mock"`,后端不会发真实短信,只会返回固定 mock 验证码;另外 `npm run api-server` 过去曾让 `.env` 覆盖 `.env.local`,导致本地真实短信配置被错误压回默认值。
|
||||
- 处理:真实短信联调时把 `.env.local` 的 `SMS_AUTH_PROVIDER` 显式设为 `aliyun`,然后重启 `api-server`;如果只想验证 UI 和账号链路,则保留 `mock` 并使用 `SMS_AUTH_MOCK_VERIFY_CODE`。
|
||||
- 验证:`GET /api/auth/login-options` 返回 `["phone","password"]`,`api-server` 日志里 `provider=aliyun` 才说明真实短信链路已生效。
|
||||
- 关联:`scripts/api-server-dev.mjs`、`docs/technical/AUTH_LOGIN_OPTIONS_DESIGN_2026-04-21.md`、`docs/technical/PHONE_SMS_REAL_PROVIDER_MANUAL_VERIFICATION_RUNBOOK_2026-04-23.md`。
|
||||
|
||||
## 手机验证码登录 500 先查短信 provider 语义
|
||||
|
||||
- 现象:登录弹窗手机号验证码登录失败,浏览器看到 `POST /api/auth/phone/login 500`,后端日志里同时出现阿里云短信 `UNKNOWN`、`biz.FREQUENCY` 或 `check frequency failed`。
|
||||
|
||||
127
.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md
Normal file
127
.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md
Normal file
@@ -0,0 +1,127 @@
|
||||
---
|
||||
name: genarrative-dev-stack-port-routing
|
||||
short_description: 修改 Genarrative 本地 dev 启动端口、代理目标、端口冲突处理时使用。
|
||||
description: 在 Genarrative 中修改 npm run dev / npm run dev:rust / npm run dev:web 的本地启动端口、端口可用性探测、端口漂移、SpacetimeDB publish server、api-server 环境变量、Vite 代理目标和后台 admin-web 启动串联时使用。
|
||||
version: 1.0.0
|
||||
author: Hermes Agent
|
||||
license: MIT
|
||||
metadata:
|
||||
hermes:
|
||||
tags: [Genarrative, dev-stack, 端口探测, Vite, api-server, SpacetimeDB, npm-run-dev]
|
||||
related_skills: [genarrative-admin-backoffice]
|
||||
---
|
||||
|
||||
# Genarrative 本地 dev 启动端口与代理目标串联流程
|
||||
|
||||
用于维护 Genarrative 本地开发栈启动脚本,重点覆盖 `npm run dev` / `npm run dev:rust` / `npm run dev:web` 的端口检查、端口漂移和后续流程目标传递。
|
||||
|
||||
## 适用场景
|
||||
|
||||
- 修改 `scripts/dev-rust-stack.sh`、`scripts/dev-web-rust.mjs`、`scripts/dev-stack-port-utils.mjs`。
|
||||
- 处理 `3000`、`3101`、`3102`、`8082` 等端口被占用导致本地开发栈启动失败。
|
||||
- 排查 Vite 代理仍指向旧 api-server 端口、前端打开了旧 dev server、后台代理错配。
|
||||
- 调整 SpacetimeDB standalone、publish、Rust `api-server`、主站 Vite、后台 Vite 的启动顺序。
|
||||
- 修改本地联调文档或 `.hermes/shared-memory/pitfalls.md` 中的 dev 启动口径。
|
||||
|
||||
## 当前端口职责
|
||||
|
||||
默认优先端口:
|
||||
|
||||
1. 主站 Vite:`3000`,对浏览器通常展示为 `http://127.0.0.1:<web-port>/`。
|
||||
2. Rust `api-server`:`8082`,健康检查为 `http://127.0.0.1:<api-port>/healthz`。
|
||||
3. SpacetimeDB standalone:`3101`,健康检查为 `http://127.0.0.1:<spacetime-port>/v1/ping`。
|
||||
4. 后台 Vite:`3102`,后台地址为 `http://127.0.0.1:<admin-web-port>/admin/`。
|
||||
|
||||
端口不可用时,脚本会从优先端口开始向后寻找可用端口。后续流程必须以解析后的实际端口为准,不能继续使用默认端口。
|
||||
|
||||
## 实现入口
|
||||
|
||||
- `package.json`
|
||||
- `dev` 和 `dev:rust`:执行 `node scripts/run-bash-script.mjs scripts/dev-rust-stack.sh`。
|
||||
- `dev:web`:执行 `node scripts/dev-web-rust.mjs`。
|
||||
- `scripts/dev-stack-port-utils.mjs`
|
||||
- `isPortAvailable(...)`:探测端口是否可监听。
|
||||
- `findAvailablePort(...)`:从优先端口向后寻找可用端口,`0` 表示申请临时端口。
|
||||
- `resolveDevStackPorts(...)`:一次性解析 SpacetimeDB、api-server、主站 Vite、后台 Vite 端口,并避免本次解析结果互相冲突。
|
||||
- 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`。
|
||||
- `scripts/dev-rust-stack.sh`
|
||||
- 解析 CLI 参数后,先计算 `API_TARGET_HOST` 与 `ADMIN_WEB_TARGET_HOST`。
|
||||
- 调用 `resolve_dev_stack_ports` 覆盖 `SPACETIME_PORT`、`API_PORT`、`WEB_PORT`、`ADMIN_WEB_PORT`。
|
||||
- 再构造 `SPACETIME_SERVER` 和 `RUST_SERVER_TARGET`。
|
||||
- `scripts/dev-web-rust.mjs`
|
||||
- 单独启动主站前端时,也先用 `findAvailablePort` 检查 `WEB_PORT` / 默认 `3000`。
|
||||
|
||||
## 必须保持的传递链路
|
||||
|
||||
`npm run dev` / `npm run dev:rust` 中端口解析后,必须同步到以下位置:
|
||||
|
||||
1. SpacetimeDB 启动:`spacetime start --listen-addr "${SPACETIME_HOST}:${SPACETIME_PORT}"`。
|
||||
2. SpacetimeDB 发布:`spacetime publish ... --server "${SPACETIME_SERVER}"`。
|
||||
3. Rust api-server:`GENARRATIVE_API_HOST`、`GENARRATIVE_API_PORT`、`GENARRATIVE_SPACETIME_SERVER_URL`、`GENARRATIVE_SPACETIME_DATABASE`。
|
||||
4. api-server 健康检查:`wait_for_api_server "${RUST_SERVER_TARGET}/healthz" ...`。
|
||||
5. 主站 Vite:`RUST_SERVER_TARGET`、`GENARRATIVE_RUNTIME_SERVER_TARGET`、`ADMIN_WEB_TARGET`、`ADMIN_WEB_PORT`、`--port=${WEB_PORT}`、`--host=${WEB_HOST}`。
|
||||
6. 后台 Vite:`ADMIN_API_TARGET`、`GENARRATIVE_API_TARGET`、`GENARRATIVE_API_PORT`、`--port=${ADMIN_WEB_PORT}`。
|
||||
7. 控制台日志:`[dev:ports]` 和 `[dev:rust] web/admin web/rust api/spacetime` 必须显示最终实际地址。
|
||||
|
||||
如果只改了其中一段,通常会出现:浏览器打开的前端可用,但 `/api/*` 代理到旧端口;后台页面可用但后台 API 失败;SpacetimeDB 启动在新端口但 publish 仍发往旧端口。
|
||||
|
||||
## 修改流程
|
||||
|
||||
1. 先读当前脚本和文档:
|
||||
- `scripts/dev-stack-port-utils.mjs`
|
||||
- `scripts/dev-rust-stack.sh`
|
||||
- `scripts/dev-web-rust.mjs`
|
||||
- `docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md`
|
||||
- `.hermes/shared-memory/pitfalls.md`
|
||||
2. 优先改公共端口工具,不要把端口探测逻辑复制到多个脚本。
|
||||
3. 对 Bash 脚本只做局部补丁,避免整文件重写导致中文注释或换行大面积变化。
|
||||
4. 修改 `dev-rust-stack.sh` 时确认变量顺序:
|
||||
- 先有 `REPO_ROOT`。
|
||||
- 再计算 `API_TARGET_HOST` / `ADMIN_WEB_TARGET_HOST`。
|
||||
- 再调用端口解析工具。
|
||||
- 再构造 `SPACETIME_SERVER` / `RUST_SERVER_TARGET`。
|
||||
5. 修改 `dev:web` 时不要自动改后端目标策略;`dev:web` 只负责主站 Vite 端口可用性与已有后端目标选择。
|
||||
6. 同步更新技术文档和团队共享记忆。
|
||||
|
||||
## 测试与验证
|
||||
|
||||
最小验证:
|
||||
|
||||
```bash
|
||||
bash -n scripts/dev-rust-stack.sh
|
||||
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
|
||||
```
|
||||
|
||||
端口冲突回归测试建议:
|
||||
|
||||
1. 用测试或临时 Node server 占用某个优先端口。
|
||||
2. 调用 `findAvailablePort`,断言结果大于被占用端口。
|
||||
3. 调用 `resolveDevStackPorts`,断言四个结果互不相同。
|
||||
4. 如果实际启动完整栈,观察控制台:
|
||||
- `[dev:ports] ... 不可用,改用 ...`
|
||||
- `[dev:rust] rust api: http://...:<actual-api-port>`
|
||||
- `[dev:rust] spacetime: http://...:<actual-spacetime-port>`
|
||||
- 主站和后台 Vite 启动端口与日志一致。
|
||||
|
||||
完整启动属于长驻进程。需要 smoke 时用 background 方式启动,并另开命令检查 `/healthz`、`/v1/ping` 和页面端口;不要等待 `npm run dev` 自然退出。
|
||||
|
||||
## 常见坑
|
||||
|
||||
1. **只让 Vite 自己漂移端口。** 这样终端可能出现可访问前端,但脚本和文档仍认为是 `3000`,后台目标或日志会错。
|
||||
2. **只改 SpacetimeDB start,不改 publish。** standalone 可能监听新端口,但 publish 仍连旧 `3101`。
|
||||
3. **只改 `GENARRATIVE_API_PORT`,不改 `RUST_SERVER_TARGET`。** api-server 已在新端口监听,但 Vite 代理仍打旧端口。
|
||||
4. **使用 `0.0.0.0` 作为浏览器访问地址。** 监听可以是 `0.0.0.0`,展示给用户和健康检查通常用 `127.0.0.1`。
|
||||
5. **端口探测和实际启动之间存在竞态。** 已经探测可用的端口仍可能被外部进程抢占;SpacetimeDB 启动后仍要解析实际监听地址,api-server 和 Vite 失败时要打印清晰日志。
|
||||
6. **运行全仓库 lint 误判。** 当前仓库可能有既有 lint 问题。验证本功能时优先运行定向测试、Bash 语法检查、编码检查,并在最终说明中区分既有 lint 失败与本次改动。
|
||||
|
||||
## 验收清单
|
||||
|
||||
- [ ] 端口工具有测试覆盖端口被占用和多端口互斥解析。
|
||||
- [ ] `dev-rust-stack.sh` 通过 `bash -n`。
|
||||
- [ ] `npm run dev` / `npm run dev:rust` 的 SpacetimeDB、publish、api-server、主站 Vite、后台 Vite 都使用实际端口。
|
||||
- [ ] `npm run dev:web` 在主站端口不可用时能切换到可用端口。
|
||||
- [ ] 文档同步更新 `docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md`。
|
||||
- [ ] 长期踩坑同步更新 `.hermes/shared-memory/pitfalls.md`。
|
||||
- [ ] 修改中文文件后运行 `npm run check:encoding`。
|
||||
Reference in New Issue
Block a user